Как в запросе 1С проверить поле на NULL и корректно получить УникальныйИдентификатор

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с языком запросов 1С программисты часто сталкиваются с ситуацией, когда при левом соединении таблиц необходимо обработать отсутствие данных (NULL). Казалось бы, стандартная конструкция ВЫБОР КОГДА ... ЕСТЬ NULL должна решать задачу, но при попытке получить УникальныйИдентификатор (UUID) ссылки поведение системы становится непредсказуемым. Рассмотрим подробнее, почему возникают ошибки типизации и как правильно выводить идентификаторы в результат запроса.

Анализ проблемы: конфликт типов в одной колонке

Разберем типичную ситуацию. Допустим, мы выполняем левое соединение справочника Кассы со справочником Склады. Если склад не найден, мы хотим получить пустую ссылку, а если найден — его уникальный идентификатор. Типичный ошибочный код выглядит так:


ВЫБРАТЬ
    ВЫБОР
        КОГДА Склады.Ссылка ЕСТЬ NULL
            ТОГДА ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
        ИНАЧЕ УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Склады.Ссылка)
    КОНЕЦ КАК Магазин
ИЗ
    Справочник.Кассы КАК Кассы
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Склады КАК Склады
    ПО Кассы.Подразделение = Склады.Подразделение

В данном примере в одной колонке Магазин система пытается совместить два принципиально разных типа данных: Ссылка (когда результат NULL) и УникальныйИдентификатор (когда ссылка существует). Платформа 1С при формировании результата запроса определяет тип колонки. Если она видит, что в одной из веток возвращается ссылка, она может принудительно типизировать всю колонку как ссылочную. В итоге вместо ожидаемого UUID в результате мы увидим либо пустую ссылку, либо некорректно отображаемые данные.

Решение №1: Приведение к единому типу в запросе

Для того чтобы запрос работал корректно, необходимо, чтобы все ветки оператора ВЫБОР возвращали значения одного и того же типа. Поскольку нам нужен идентификатор, мы должны преобразовать пустую ссылку в идентификатор еще внутри запроса. Посмотрим на правильный вариант:


ВЫБРАТЬ
    ВЫБОР
        КОГДА Склады.Ссылка ЕСТЬ NULL
            ТОГДА УНИКАЛЬНЫЙИДЕНТИФИКАТОР(ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка))
        ИНАЧЕ УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Склады.Ссылка)
    КОНЕЦ КАК Магазин
ИЗ
    Справочник.Кассы КАК Кассы
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Склады КАК Склады
    ПО Кассы.Подразделение = Склады.Подразделение

В этом случае обе ветви возвращают тип УникальныйИдентификатор. Платформа понимает, что колонка типизирована однозначно, и корректно выводит строковое представление UUID.

Решение №2: Использование функции ЕСТЬNULL

Функция ЕСТЬNULL работает быстрее, чем оператор ВЫБОР, но она еще более требовательна к типам. Если вы используете её для работы с идентификаторами, помните: второй параметр (значение замены) должен строго соответствовать типу первого параметра. Проанализируем пример:


// Это может вызвать ошибку или некорректное приведение типов:
ЕСТЬNULL(УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Склады.Ссылка), "") 

// Это правильный способ:
ЕСТЬNULL(УНИКАЛЬНЫЙИДЕНТИФИКАТОР(Склады.Ссылка), УНИКАЛЬНЫЙИДЕНТИФИКАТОР(ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)))

Особенности типа УникальныйИдентификатор в 1С

Важно понимать технические ограничения, которые накладывает платформа на работу с этим типом данных в запросах:

  1. Ограничения группировки: Поля с типом УникальныйИдентификатор нельзя использовать в секции СГРУППИРОВАТЬ ПО. Если вам нужно сгруппировать данные по UUID, сначала получите ссылку, сгруппируйте по ней, а идентификатор получайте уже в итоговой выборке.
  2. Сортировка: Платформа не позволяет выполнять УПОРЯДОЧИТЬ ПО для полей, возвращаемых функцией УНИКАЛЬНЫЙИДЕНТИФИКАТОР().
  3. Составные типы: В метаданных невозможно создать поле составного типа, включающее в себя УИД и Ссылку одновременно. Язык запросов пытается следовать этому же ограничению при формировании временных таблиц и результатов.
  4. Двоичные данные: На уровне СУБД ссылка хранится как 16-байтовое поле. При определенных конфликтах типов в запросе 1С может вернуть не UUID, а объект ДвоичныеДанные. Это происходит, когда оптимизатор запросов не может сопоставить типы и выдает "сырое" содержимое поля базы данных.

Рекомендации по проектированию запросов

Проанализируем ситуацию: стоит ли вообще получать UUID непосредственно в запросе? В большинстве случаев лучшей практикой будет следующий алгоритм:

  1. В запросе получайте саму Ссылку, обрабатывая NULL стандартным образом: ЕСТЬNULL(Склады.Ссылка, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)).
  2. Если вам нужен именно строковый идентификатор для передачи во внешние системы (например, через JSON или XML), преобразуйте его уже в коде 1С при обходе результата запроса:

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    // Работаем со ссылкой, преобразуя её в УИД только при необходимости
    ИдентификаторСтрокой = Строка(Выборка.Магазин.УникальныйИдентификатор());
КонецЦикла;

Такой подход избавляет от проблем с типизацией в SQL-движке, позволяет использовать индексацию по ссылочным полям во временных таблицах и делает код более читаемым. Выясним причину, почему разработчики часто пытаются сделать это в запросе — обычно это связано с желанием минимизировать постобработку данных, но в случае с типом УникальныйИдентификатор это часто приводит к обратным результатам и ошибкам Internal consistency error на старых версиях платформы.

Резюме: Если вам критично получить UUID именно в запросе, следите за тем, чтобы все условия в операторе ВЫБОР возвращали результат функции УНИКАЛЬНЫЙИДЕНТИФИКАТОР(). Не смешивайте ссылки, строки и идентификаторы в рамках одной колонки.

← На главную