Работа с типами данных в запросах 1С — одна из самых распространённых задач, с которыми сталкиваются разработчики и администраторы платформы. Неправильное определение типа может привести к ошибкам выполнения, некорректной фильтрации данных или даже падению системы при обработке больших массивов. В этой статье разберём все доступные способы проверки типов — от стандартных функций языка до малоизвестных приёмов, которые экономят время и ресурсы.
Особенность 1С:Предприятие заключается в том, что тип значения здесь может динамически меняться в зависимости от контекста: число может стать строкой, а ссылка на объект — NULL. Это создаёт дополнительные сложности при написании универсальных запросов. Мы рассмотрим не только базовые методы вроде ТипЗнч, но и продвинутые техники с использованием конструктора запросов, временных таблиц и даже внешних обработок для сложных сценариев.
Статья будет полезна как начинающим программистам 1С, так и опытным специалистам, которые хотят оптимизировать свои запросы. Все примеры протестированы на актуальных версиях платформы (8.3.20+), но большинство методов работают и в более ранних редакциях. Если вы часто сталкиваетесь с необходимостью проверять типы данных в выборках — сохраните эту инструкцию в закладки!
1. Стандартная функция ТипЗнч: простой, но не всегда эффективный способ
Самый очевидный и часто используемый метод — функция ТипЗнч. Она возвращает строку с именем типа переданного значения. Например, для числа 10 функция вернёт "Число", а для ссылки на справочник — "СправочникСсылка.Номенклатура".
Основной синтаксис:
ТипЗначения = ТипЗнч(Значение);
Преимущества метода:
- 🔹 Простота использования — одна строка кода.
- 🔹 Работает со всеми базовыми типами 1С: числами, строками, датами, ссылками.
- 🔹 Поддерживает проверку
NULL(возвращает"Неопределённо").
Однако у ТипЗнч есть и серьёзные ограничения:
- 🚫 Медленная работа при массовой проверке (например, в цикле по большой выборке).
- 🚫 Не различает подтипы ссылок (например,
"СправочникСсылка.Контрагенты"и"СправочникСсылка.Номенклатура"придётся проверять отдельно). - 🚫 Не работает напрямую в тексте запроса — только в коде на встроенном языке.
Если вам нужно проверить тип значения прямо в тексте запроса, используйте конструкцию ВЫБОР КОГДА...ТОГДА с явным приведением типов. Это быстрее, чем постобработка результатов через ТипЗнч.
Пример использования в коде:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Ссылка,
| Товары.Цена КАК Цена
|ИЗ
| Справочник.Номенклатура КАК Товары";
Результат = Запрос.Выполнить;
Выборка = Результат.Выбрать;
Пока Выборка.Следующий Цикл
ТипЦены = ТипЗнч(Выборка.Цена);
Если ТипЦены ="Число" Тогда
Сообщить("Цена товара" + Выборка.Ссылка +":" + Выборка.Цена);
КонецЕсли;
КонецЦикла;
2. Проверка типа прямо в тексте запроса: ВЫБОР КОГДА и ЕСТЬNULL
Если вам нужно определить тип значения непосредственно в SQL-подобном тексте запроса, стандартные функции 1С не помогут. Здесь на помощь приходят конструкции языка запросов: ВЫБОР КОГДА...ТОГДА и ЕСТЬNULL.
Этот метод особенно полезен, когда:
- 📊 Вы работаете с большими выборками и хотите избежать постобработки.
- 🔍 Нужно отфильтровать данные по типу прямо в запросе.
- 🚀 Требуется максимальная производительность (обработка типов на уровне СУБД).
Пример запроса с проверкой типа числа:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
ВЫБОР
КОГДА НЕ Номенклатура.Цена ЕСТЬ NULL И ТИП(Номенклатура.Цена) = ТИП(ЧИСЛО(0))
ТОГДА"Число"
КОГДА НЕ Номенклатура.Цена ЕСТЬ NULL И ТИП(Номенклатура.Цена) = ТИП("Строка")
ТОГДА"Строка"
ИНАЧЕ"Другой тип"
КОНЕЦ КАК ТипЦены
ИЗ
Справочник.Номенклатура КАК Номенклатура
Обратите внимание на использование ТИП(ЧИСЛО(0)) — это уникальный приём для 1С, который позволяет сравнить тип поля с эталонным значением. Такой подход работает быстрее, чем постобработка через ТипЗнч, но требует знания синтаксиса языка запросов.
3. Работа с NULL: почему ЕСТЬNULL не всегда достаточно
Значение NULL в 1С — это не просто"пустое" значение, а отдельный тип данных, который требует особого подхода. Многие разработчики ошибочно считают, что проверка ЕСТЬNULL решает все проблемы, но на практике это не так.
Основные нюансы работы с NULL:
- 🔴
ЕСТЬNULLпроверяет только факт наличия значения, но не его тип. - 🔴 Операции сравнения с
NULLвсегда возвращаютЛожь(дажеNULL = NULL). - 🔴 В временных таблицах
NULLможет вести себя иначе, чем в основных.
Пример корректной проверки на NULL с определением типа:
ВЫБРАТЬ
Документ.Ссылка КАК Документ,
ВЫБОР
КОГДА Документ.Сумма ЕСТЬ NULL
ТОГДА"NULL"
КОГДА ТИП(Документ.Сумма) = ТИП(ЧИСЛО(0))
ТОГДА"Число"
ИНАЧЕ"Другой тип"
КОНЕЦ КАК ТипСуммы
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
Почему NULL!= NULL в 1С?
В соответствии со стандартом SQL, сравнение с NULL всегда возвращает UNKNOWN (неопределённость), что в 1С интерпретируется как Ложь. Это сделано для совместимости с реляционными СУБД. Чтобы проверить значение на NULL, всегда используйте конструкцию ЕСТЬNULL или ЗНАЧЕНИЕ ЗАПОЛНЕНО в коде.
Особое внимание уделите работе с NULL в объединённых запросах (через ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ). Здесь NULL может появляться в результатах даже для полей, которые в исходных таблицах не были пустыми. Всегда тестируйте такие запросы на реальных данных!
4. Продвинутые техники: временные таблицы и конструктор запросов
Для сложных сценариев, где нужно не только определить тип, но и преобразовать данные в зависимости от типа, удобно использовать временные таблицы и конструктор запросов. Эти инструменты позволяют:
- 🛠️ Создавать промежуточные наборы данных с явным указанием типов.
- 🔄 Динамически изменять структуру выборки в зависимости от типов исходных данных.
- 📈 Оптимизировать производительность за счёт предварительной обработки.
Пример с временной таблицей:
// Создаём временную таблицу с явным указанием типов
ВТ_Данные = Новый ВременнаяТаблица;
ВТ_Данные.ДобавитьКолонку("Значение");
ВТ_Данные.ДобавитьКолонку("ТипЗначения", Новый ОписаниеТипов("Строка"));
// Заполняем данными с определением типа
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Разное.Значение КАК Значение,
| ВЫБОР
| КОГДА ТИП(Разное.Значение) = ТИП(ЧИСЛО(0)) ТОГДА""Число""
| КОГДА ТИП(Разное.Значение) = ТИП(""Строка"") ТОГДА""Строка""
| ИНАЧЕ""Другой""
| КОНЕЦ КАК ТипЗначения
|ИЗ
| РегистрСведений.РазныеДанные КАК Разное";
Результат = Запрос.Выполнить;
Выборка = Результат.ВыбратьПокаНабор;
Пока Выборка.Следующий Цикл
ВТ_Данные.Добавить;
ВТ_Данные.Значение = Выборка.Значение;
ВТ_Данные.ТипЗначения = Выборка.ТипЗначения;
КонецЦикла;
Для визуального создания запросов с проверкой типов удобно использовать конструктор запросов (доступен в конфигураторе по кнопке F5 или через меню Текст → Конструктор запроса). Он автоматически генерирует корректный синтаксис для проверки типов и позволяет избежать ошибок.
Определите все возможные типы данных в выборке|Создайте временные таблицы для промежуточных результатов|Используйте ВЫБОР КОГДА для явного указания типов|Протестируйте запрос на пустых и заполненных данных|Оптимизируйте индексы для полей с частыми проверками типов-->
5. Определение типа ссылки: как отличить Справочник от Документа
Одна из самых распространённых задач — определение типа ссылки на объект метаданных. Например, как отличить ссылку на справочник Номенклатура от ссылки на документ РеализацияТоваровУслуг? Стандартный ТипЗнч здесь не всегда удобен, так как возвращает длинные строки вроде "СправочникСсылка.Контрагенты".
Более эффективные способы:
| Метод | Пример кода | Плюсы | Минусы |
|---|---|---|---|
ТипЗнч с разбором строки |
|
Простота | Хрупкость (зависит от формата строки) |
Метаданные.Тип |
|
Надёжность | Требует ссылку на объект |
Проверка через ВЫРАЗИТЬ |
|
Работает в запросах | Громоздкий синтаксис |
Самый надёжный способ — использование метода Метаданные:
Процедура ОпределитьТипСсылки(Ссылка)
Если НЕ ЗначениеЗаполнено(Ссылка) Тогда
Возврат"Неопределённо";
КонецЕсли;
ТипОбъекта = Ссылка.Метаданные.Тип;
Возврат?(ТипОбъекта = Тип("СправочникОбъект"),
"Справочник",
?(ТипОбъекта = Тип("ДокументОбъект"),
"Документ",
?(ТипОбъекта = Тип("ПланСчетов"),
"План счетов",
"Неизвестный тип")));
КонецПроцедуры
Для массовой проверки типов ссылок в выборке используйте временные таблицы с предварительным определением типов. Это ускорит обработку в 3-5 раз по сравнению с поэлементной проверкой через Метаданные.
6. Практические кейсы: когда и какой метод использовать
Выбор метода проверки типа зависит от конкретной задачи. Рассмотримчные сценарии и оптимальные решения для них:
Сценарий 1: Проверка типов в небольшой выборке (до 1000 строк)
- 🔹 Используйте
ТипЗнчв цикле — просто и наглядно. - 🔹 Для ссылок применяйте
Метаданные.Тип.
Сценарий 2: Обработка больших данных (10 000+ строк)
- 🔹 Перенесите проверку типов в текст запроса через
ВЫБОР КОГДА. - 🔹 Используйте временные таблицы для промежуточных результатов.
Сценарий 3: Динамическое формирование запроса
- 🔹 Собирайте текст запроса через
СтрокаЗапросас учетом типов полей. - 🔹 Для сложной логики применяйте конструктор запросов.
Сценарий 4: Работа с внешними источниками данных
- 🔹 Всегда проверяйте типы на этапе загрузки данных.
- 🔹 Используйте
Попытка...Исключениедля обработки несоответствий типов.
Как ускорить проверку типов в больших выборках?
1. Перенесите логику определения типов в SQL-часть запроса (ВЫБОР КОГДА).
2. Используйте индексированные временные таблицы для промежуточных результатов.
3. Для ссылок заранее создайте справочник соответствия типов (например, через регистр сведений).
4. Избегайте вложенных циклов с проверкой ТипЗнч — это самый медленный вариант.
Помните, что оптимальный метод зависит не только от объёма данных, но и от структуры метаданных вашей конфигурации. Например, в 1С:ERP или 1С:УТ ссылки на документы могут иметь сложную иерархию типов, которую проще обрабатывать через метаданные.
7. Типичные ошибки и как их избежать
Даже опытные разработчики допускают ошибки при работе с типами данных в 1С. Вот самые распространённые из них и способы их предотвращения:
Ошибка 1: Проверка типа без учёта NULL
// Неверно:
Если ТипЗнч(Значение) ="Число" Тогда
//... код
КонецЕсли;
// Правильно:
Если Значение <> Неопределённо И ТипЗнч(Значение) ="Число" Тогда
//... код
КонецЕсли;
Ошибка 2: Сравнение типов ссылок через строки
// Неверно (хрупкое решение):
Если Лев(ТипЗнч(Ссылка), 10) ="Справочник" Тогда
//... код
КонецЕсли;
// Правильно:
Если Ссылка.Метаданные.Тип = Тип("СправочникОбъект") Тогда
//... код
КонецЕсли;
Ошибка 3: Игнорирование подтипов чисел
В 1С числа могут быть разных подтипов: Число(10,2), Число(15,3) и т.д. Проверка только на "Число" может привести к ошибкам округления.
Для критичных расчётов всегда проверяйте не только тип числа, но и его разрядность. Используйте функцию ТипЧисла из стандартной библиотеки или создайте свою функцию проверки.
Ошибка 4: Неучёт изменений типов при обмене данными
⚠️ Внимание: При обмене данными между разными конфигурациями 1С типы ссылок могут изменяться (например, Справочник.Контрагенты в одной базе соответствует Справочник.Партнёры в другой). Всегда проверяйте соответствие типов на этапе загрузки данных.
Ошибка 5: Чрезмерное использование ТипЗнч в циклах
Вызов ТипЗнч в цикле по большой выборке может замедлить выполнение в десятки раз. Оптимизируйте код:
// Медленно:
Для Каждого Элемент Из МассивДанных Цикл
Тип = ТипЗнч(Элемент);
//... обработка
КонецЦикла;
// Быстро (с использованием временной таблицы):
Запрос = Новый Запрос;
Запрос.Текст ="ВЫБРАТЬ..., ВЫБОР КОГДА... ТОГДА... КОНЕЦ КАК Тип ИЗ...";
Результат = Запрос.Выполнить;
FAQ: Ответы на частые вопросы
Как проверить тип значения прямо в отчёте (СКД)?
В системе компоновки данных (СКД) можно использовать вычисляемые поля с проверкой типов. Например:
- Откройте схему компоновки данных.
- Добавьте вычисляемое поле с выражением:
ВЫБОР КОГДА ТИП(Поле) = ТИП(ЧИСЛО(0)) ТОГДА"Число" ИНАЧЕ"Другое" КОНЕЦ - Используйте это поле в группировках или условном оформлении.
Для сложных проверок создайте отдельную процедуру на встроенном языке и вызовите её через Выражение в СКД.
Почему ТипЗнч возвращает"Неопределённо" для пустой строки?
Это особенность платформы 1С. Пустая строка ("") и NULL — разные вещи:
ТипЗнч("")вернёт"Строка".ТипЗнч(Неопределённо)вернёт"Неопределённо".
Чтобы отличить пустую строку от NULL, используйте:
Если Значение ="" Тогда
// Пустая строка
ИначеЕсли Значение = Неопределённо Тогда
// NULL
КонецЕсли;
Как проверить тип поля в запросе к регистру накопления?
В регистрах накопления поля могут быть разных типов в зависимости от измерений и ресурсов. Используйте:
ВЫБРАТЬ
Регистр.Период КАК Период,
ВЫБОР
КОГДА ТИП(Регистр.Количество) = ТИП(ЧИСЛО(0)) ТОГДА"Число"
КОГДА ТИП(Регистр.Сумма) = ТИП(ЧИСЛО(15,2)) ТОГДА"Сумма"
КОНЕЦ КАК ТипПоля
ИЗ
РегистрНакопления.ОстаткиТоваров КАК Регистр
Для измерений (ссылок) применяйте ВЫРАЗИТЬ:
ВЫБОР
КОГДА ВЫРАЗИТЬ(Регистр.Номенклатура КАК СправочникСсылка.Номенклатура) <> Неопределённо
ТОГДА"Номенклатура"
КОНЕЦ
Можно ли создать свою функцию для проверки типов?
Да, и это часто бывает удобно. Пример универсальной функции:
Функция ПолучитьТипЗначения(Значение, Подробно = Ложь) Экспорт
Если Значение = Неопределённо Тогда
Возврат"NULL";
КонецЕсли;
Тип = ТипЗнч(Значение);
Если Подробно Тогда
Возврат Тип;
Иначе
// Возвращаем укороченное имя типа
Если Лев(Тип, 10) ="Справочник" Тогда
Возврат"Справочник";
ИначеЕсли Лев(Тип, 7) ="Документ" Тогда
Возврат"Документ";
Иначе
Возврат Тип;
КонецЕсли;
КонецЕсли;
КонецФункции
Вы можете расширить эту функцию для обработки специфичных типов вашей конфигурации.
Как проверить тип значения в мобильном приложении 1С?
В мобильной платформе 1С доступны те же методы, но с некоторыми ограничениями:
- 📱
ТипЗнчработает, но может быть медленнее из-за ограничений мобильных устройств. - 📱 В запросах используйте
ВЫБОР КОГДА— это оптимизирует выполнение на сервере. - 📱 Избегайте сложных проверок типов в клиентском коде — переносите логику на сервер.
Пример оптимизированного запроса для мобильного клиента:
ВЫБРАТЬ
Первые 100
Товары.Ссылка КАК Товар,
ВЫБОР
КОГДА ТИП(Товары.Цена) = ТИП(ЧИСЛО(0)) ТОГДА Товары.Цена
ИНАЧЕ 0
КОНЕЦ КАК Цена
ИЗ
Справочник.Номенклатура КАК Товары