Работа с типами данных в запросах 1С:Предприятие — одна из самых распространённых задач, с которыми сталкиваются разработчики при создании отчётов, обработок или сложных выборок. Ошибки в сравнении типов могут приводить к некорректным результатам, падению производительности или даже ошибкам выполнения. В этой статье мы разберём 5 основных способов сравнения типов в запросах, их особенности и области применения.
Особенность 1С заключается в том, что система оперирует не только стандартными типами (число, строка, дата), но и ссылочными типами (справочники, документы), а также составными типами (массивы, структуры). При этом синтаксис запросов имеет свои нюансы, которые важно учитывать. Например, оператор ТИП() работает иначе, чем функция ТипЗнч() в встроенном языке. Мы рассмотрим оба подхода и покажем, когда какой уместнее использовать.
Статья будет полезна как начинающим разработчикам, которые только осваивают запросы, так и опытным специалистам, желающим оптимизировать существующий код. Все примеры приведены для актуальных версий платформы 1С:Предприятие 8.3 (включая последние релизы). Если вы работаете со старшими версиями (8.2 или 8.1), некоторые конструкции могут требовать адаптации — об этом мы тоже упомянем в соответствующих разделах.
1. Оператор ТИП() — базовый способ проверки типа
Оператор ТИП() — самый простой и интуитивно понятный способ определить тип значения прямо в тексте запроса. Он возвращает строку с именем типа, которую затем можно сравнить с эталонным значением. Синтаксис минималистичен:
ТИП(Выражение)
Например, чтобы отфильтровать строки, где поле СуммаДокумента является числом, напишем:
ВЫБРАТЬ
Номер,
СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг
ГДЕ
ТИП(СуммаДокумента) = "Число"
Важный нюанс: ТИП() возвращает имя типа на русском языке (например, "СправочникСсылка.Номенклатура"), поэтому сравнение должно учитывать локализацию платформы. Если вы работаете с англоязычной конфигурацией, используйте английские названия типов ("CatalogRef.Nomenclature").
- ✅ Простота использования — не требует дополнительных функций.
- ✅ Работает во всех версиях платформы 8.x.
- ⚠️ Чувствителен к локализации (рус/англ названия типов).
- ⚠️ Не позволяет проверять производные типы (например, "Число(10,2)").
Если вам нужно проверить тип поля в динамическом запросе (где имя типа заранее неизвестно), используйте конструкцию ВЫБОР КОГДА ТИП(Поле) = "Строка" ТОГДА 1 ИНАЧЕ 0 КОНЕЦ для условной логики.
2. Функция ВЫРАЗИТЬ() — приведение и сравнение
Функция ВЫРАЗИТЬ() предназначена для явного приведения типов в запросах. Однако её можно использовать и для косвенной проверки типа: если приведение проходит успешно, значит исходное значение соответствует целевому типу. Синтаксис:
ВЫРАЗИТЬ(Выражение КАК Тип)
Пример: проверка, что поле ДатаДокумента является датой:
ВЫБРАТЬ
Номер,
ДатаДокумента
ИЗ
Документ.ПоступлениеТоваров
ГДЕ
ВЫРАЗИТЬ(ДатаДокумента КАК Дата) <> NULL
Если ДатаДокумента не является датой, функция вернёт NULL, и строка не попадёт в результат. Этот метод удобен, когда нужно не только проверить тип, но и сразу привести его к нужному формату.
⚠️ Внимание: ФункцияВЫРАЗИТЬ()может изменять значение при приведении (например, обрезать дробную часть числа или округлять дату). Если вам важно сохранить исходное значение, используйтеТИП()илиЕСТЬNULL().
| Исходный тип | Целевой тип | Результат приведения | Примечание |
|---|---|---|---|
"123" (строка) |
Число |
123 |
Успешное преобразование |
"31.12.2023" (строка) |
Дата |
31.12.2023 0:00:00 |
Добавляется время 00:00:00 |
"АБВ" (строка) |
Число |
NULL |
Некорректное преобразование |
100.55 (число) |
Число(10,0) |
101 |
Округление до целого |
3. Конструкция ВЫБОР КОГДА — гибкая проверка с условиями
Если вам нужно не просто проверить тип, а выполнить разные действия в зависимости от типа значения, используйте конструкцию ВЫБОР КОГДА. Она позволяет создавать сложную логику прямо в запросе без обращения к встроенному языку.
Пример: вывод разных сообщений в зависимости от типа поля ЗначениеПараметра:
ВЫБРАТЬ
ВЫБОР
КОГДА ТИП(ЗначениеПараметра) = "Число"
ТОГДА "Числовой параметр: " + СТРОКА(ЗначениеПараметра)
КОГДА ТИП(ЗначениеПараметра) = "Строка"
ТОГДА "Текстовый параметр: " + ЗначениеПараметра
КОГДА ТИП(ЗначениеПараметра) = "Дата"
ТОГДА "Дата: " + ФОРМАТ(ЗначениеПараметра, "ДЛФ=DT")
ИНАЧЕ "Неопознанный тип: " + ТИП(ЗначениеПараметра)
КОНЕЦ КАК ОписаниеПараметра
ИЗ
РегистрСведений.ПараметрыСистемы
Этот подход удобен для формирования отчётов, где данные разных типов нужно представить в унифицированном виде. Также ВЫБОР КОГДА можно комбинировать с ВЫРАЗИТЬ() для приведения типов "на лету".
Убедитесь, что все возможные типы обработаны в условии|Используйте ИНАЧЕ для неожиданных типов|Проверьте производительность при большом количестве КОГДА|Тестируйте результат на NULL-значениях-->
4. Работа со ссылочными типами: ССЫЛКА и ВИД()
Ссылочные типы (справочники, документы, планы видов характеристик) требуют особого подхода. Для них недостаточно проверить общий тип (например, "СправочникСсылка"), часто нужно узнать конкретный вид объекта (например, "Справочник.Номенклатура"). Здесь помогает функция ВИД().
Пример: выборка только номенклатуры из поля Объект, которое может содержать ссылки на разные справочники:
ВЫБРАТЬ
Объект.Наименование КАК Наименование
ИЗ
Документ.ЗаказПокупателя.Товары КАК Товары
ГДЕ
ТИП(Товары.Объект) = "СправочникСсылка"
И ВИД(Товары.Объект) = "Справочник.Номенклатура"
Функция ВИД() возвращает строку с полным именем типа, включая пространство имён (например, "Справочник.Контрагенты"). Это позволяет точно идентифицировать объект даже в случаях, когда в конфигурации есть несколько справочников с одинаковыми синонимами.
⚠️ Внимание: При изменении имен справочников или документов в конфигурации (например, при рефакторинге) запросы с явным указанием вида ВИД() = "Справочник.СтароеИмя" перестанут работать. Используйте псевдонимы или выносите имена типов в параметры запроса.
Для проверки, что значение является любой ссылкой (независимо от вида), можно использовать упрощённый синтаксис:
ГДЕ ТИП(Поле) КАК ССЫЛКА
5. Проверка составных типов: МАССИВ, СТРУКТУРА, ТАБЛИЦАЗНАЧЕНИЙ
Составные типы (массивы, структуры, таблицы значений) в запросах 1С требуют особого внимания. Для их проверки можно использовать комбинацию ТИП() и специализированных функций, таких как КОЛИЧЕСТВО() или РАЗМЕР().
Пример: фильтрация записей, где поле ДополнительныеРеквизиты является структурой с хотя бы одним элементом:
ВЫБРАТЬ
НомерДокумента
ИЗ
Документ.ЗаказПоставщику
ГДЕ
ТИП(ДополнительныеРеквизиты) = "Структура"
И КОЛИЧЕСТВО(ДополнительныеРеквизиты) > 0
Для массивов удобно использовать функцию РАЗМЕР():
ГДЕ ТИП(СписокТоваров) = "Массив" И РАЗМЕР(СписокТоваров) > 3
Обратите внимание, что в запросах 1С нельзя напрямую обращаться к элементам массива или структуры по индексу или ключу. Для этого нужно использовать механизм виртуальных таблиц или обрабатывать данные на встроенном языке после выполнения запроса.
Как работать с таблицами значений в запросах?
В запросах 1С нет прямого способа проверки типа "ТаблицаЗначений" — вместо этого используется тип "Таблица". Однако функционал работы с такими полями крайне ограничен. Например, вы можете проверить наличие таблицы:
ГДЕ ТИП(ТабличнаяЧасть) = "Таблица"
Но для доступа к данным внутри таблицы потребуется использовать конструктор запроса с объединением или обрабатывать таблицу на встроенном языке после получения результата.
6. Оптимизация запросов: индексы и производительность
Проверка типов в запросах может значительно влиять на производительность, особенно если она применяется к большим таблицам. Вот ключевые рекомендации по оптимизации:
- 🔍 Избегайте
ТИП()в условиях фильтрации для полей, по которым есть индексы. Например, если у вас есть индекс по полюДатаДокумента, условиеТИП(ДатаДокумента) = "Дата"заставит СУБД просканировать все строки, вместо использования индекса. - ⚡ Выносите проверку типов в подзапросы, если она применяется к небольшой части данных. Например:
ВЫБРАТЬ *ИЗ (
ВЫБРАТЬ
Номер,
Сумма КАК СуммаДокумента
ИЗ
Документ.Реализация
ГДЕ
ТИП(Сумма) = "Число" -- Фильтрация по типу в подзапросе
)
ГДЕ
СуммаДокумента > 1000 -- Использование индекса по числовому полю
- 📊 Используйте виртуальные таблицы для сложных проверок. Например, вместо проверки типа каждого элемента массива в основном запросе, создайте временную таблицу с предварительно отфильтрованными данными.
- 🛠️ Тестируйте запросы в консоли с включённым планом выполнения (
ОБЪЯСНИТЬ). Это поможет выявить узкие места, связанные с проверкой типов.
Критическая ошибка многих разработчиков: использование конструкций вроде ГДЕ ТИП(Поле) <> "NULL" для проверки на заполненность. Это неверно — для проверки на NULL всегда используйте оператор ЕСТЬNULL() или сравнение Поле ЕСТЬ NULL.
FAQ: Частые вопросы по сравнению типов в 1С
Можно ли в одном запросе проверить несколько возможных типов для поля?
Да, для этого используйте оператор В (аналог IN в SQL):
ГДЕ ТИП(Поле) В ("Число", "Строка", "Дата")
Это эквивалентно нескольким условиям с ИЛИ, но записывается компактнее.
Почему ТИП(Поле) = "СправочникСсылка.Номенклатура" не работает, хотя поле точно содержит номенклатуру?
Скорее всего, вы указали неполное имя типа. Попробуйте:
- Использовать
ВИД(Поле) = "Справочник.Номенклатура"вместоТИП(). - Проверить точное имя типа через
МETAДАННЫЕ().Типыв отладчике. - Учесть, что имя типа может зависеть от языка конфигурации (рус/англ).
Как сравнить тип поля с типом параметра запроса?
Используйте функцию ТИПЗНАЧ() на встроенном языке для получения имени типа параметра, а затем передайте его в запрос как строку:
// На встроенном языке
ТипПараметра = ТипЗнч(ПараметрПоиска);
// В тексте запроса
&ТипПараметра = ТипПараметра;
ВЫБРАТЬ ...
ГДЕ ТИП(Поле) = &ТипПараметра
Можно ли в запросе проверить, что поле является перечислением?
Да, для этого используйте:
ГДЕ ТИП(Поле) = "ПеречислениеСсылка.ИмяПеречисления"
Например, для перечисления ВидыОплаты:
ГДЕ ТИП(ВидОплаты) = "ПеречислениеСсылка.ВидыОплаты"
Если нужно проверить любое перечисление (независимо от вида), используйте:
ГДЕ ТИП(ВидОплаты) ПОДОБНО "ПеречислениеСсылка.%"
Почему запрос с ТИП() работает медленно на больших таблицах?
Функция ТИП() не использует индексы, так как для её выполнения СУБД должна прочитать каждое значение поля. Оптимизируйте запрос следующими способами:
- Перенесите проверку типа в подзапрос, который работает с меньшим набором данных.
- Используйте материализованные представления или регистры сведений для хранения предварительно отфильтрованных данных.
- Замените проверку типа на проверку по связанным таблицам (например, вместо
ТИП(Объект) = "ДокументСсылка.Заказ"используйте соединение с таблицей документов).
Для максимальной производительности избегайте проверки типов в условиях фильтрации по индексированным полям. Используйте ТИП() только там, где это действительно необходимо, и оптимизируйте запросы с помощью подзапросов или виртуальных таблиц.