При соединении таблиц в языке запросов 1С разработчики часто сталкиваются со значениями NULL. Типичная задача — выбрать значение из основной таблицы, а если запись или реквизит отсутствуют, подставить данные из соединенной таблицы или значение по умолчанию. Разберем по шагам, как устроена обработка NULL, почему возникают логические ошибки и как составить оптимальный запрос.
Разберем фундаментальное отличие, из-за которого часто возникают ошибки в выборках. В платформе 1С:Предприятие NULL и пустая ссылка справочника (например, ЗНАЧЕНИЕ(Справочник.РабочиеМеста.ПустаяСсылка)) — это абсолютно разные типы данных:
ЛЕВОЕ, ПРАВОЕ, ПОЛНОЕ).Если применить оператор сравнения КОГДА Поле <> ЗНАЧЕНИЕ(Справочник.РабочиеМеста.ПустаяСсылка) к значению NULL, то результатом сравнения будет не Истина, а UNKNOWN (неопределенность), которая в логических ветках воспринимается как Ложь. Поэтому обычное сравнение с пустой ссылкой не обрабатывает отсутствующие записи.
Для быстрой подстановки альтернативного значения при наличии NULL предназначена встроенная функция языка запросов ЕСТЬNULL(). Она принимает два параметра: проверяемое выражение и значение замены.
Рассмотрим синтаксис функции:
ЕСТЬNULL(ПроверяемоеПоле, ЗначениеЗамены)
Если ПроверяемоеПоле равно NULL, функция вернет ЗначениеЗамены. Если же в поле находится любое другое значение (включая пустую ссылку), функция вернет само ПроверяемоеПоле без изменений.
Посмотрим на пример, когда необходимо получить данные физического лица из справочников ИТ_КонтактныеЛица и Сотрудники, при этом физическое лицо может присутствовать только в одном из них или в обоих сразу. Напишем запрос с обработкой отсутствующих значений через ЕСТЬNULL:
ВЫБРАТЬ
ЕСТЬNULL(КонтактныеЛица.Владелец, ЗНАЧЕНИЕ(Справочник.ИТ_КонтактныеЛица.ПустаяСсылка)) КАК Владелец,
ЕСТЬNULL(КонтактныеЛица.РабМесто, Сотрудники.РабочееМесто) КАК РабочееМесто
ИЗ
Справочник.ИТ_КонтактныеЛица КАК КонтактныеЛица
ПОЛНОЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Сотрудники
ПО КонтактныеЛица.ФизЛицо = Сотрудники.ФизЛицо
ГДЕ
КонтактныеЛица.ФизЛицо = &Ссылка
ИЛИ Сотрудники.ФизЛицо = &Ссылка
Обратим внимание на условие в секции ГДЕ: обращение ФизЛицо.Ссылка = &Ссылка является избыточным, так как реквизит ФизЛицо уже содержит ссылку. Дополнительное разыменование через точку порождает лишнее соединение на уровне СУБД, поэтому пишем просто ФизЛицо = &Ссылка.
Проанализируем ситуацию, когда реквизит в соединенной таблице может быть не только NULL (строка не найдена), но и содержать пустую ссылку (строка есть, но рабочее место не заполнено). В этом случае простой функции ЕСТЬNULL будет недостаточно, так как пустая ссылка не заменится на данные сотрудника.
Для корректного решения объединим проверку ЕСТЬ NULL и проверку на равенство пустой ссылке через конструкцию ВЫБОР:
ВЫБРАТЬ
ЕСТЬNULL(КонтактныеЛица.Владелец, ЗНАЧЕНИЕ(Справочник.КонтактныеЛица.ПустаяСсылка)) КАК Владелец,
ВЫБОР
КОГДА КонтактныеЛица.РабМесто ЕСТЬ NULL
ИЛИ КонтактныеЛица.РабМесто = ЗНАЧЕНИЕ(Справочник.РабочиеМеста.ПустаяСсылка)
ТОГДА Сотрудники.РабочееМесто
ИНАЧЕ КонтактныеЛица.РабМесто
КОНЕЦ КАК РабочееМесто
ИЗ
Справочник.ИТ_КонтактныеЛица КАК КонтактныеЛица
ПОЛНОЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Сотрудники
ПО КонтактныеЛица.ФизЛицо = Сотрудники.ФизЛицо
ГДЕ
КонтактныеЛица.ФизЛицо = &Ссылка
ИЛИ Сотрудники.ФизЛицо = &Ссылка
Конструкция с ПОЛНОЕ СОЕДИНЕНИЕ и условием ИЛИ в секции ГДЕ часто приводит к неоптимальному плану выполнения на больших объемах данных, так как СУБД выполняет полное сканирование таблиц.
Если поиск выполняется по конкретному физическому лицу, построим запрос от ведущей таблицы — справочника ФизическиеЛица — с последующим левым соединением подчиненных справочников:
ВЫБРАТЬ
КонтактныеЛица.Владелец КАК Владелец,
ВЫБОР
КОГДА КонтактныеЛица.РабМесто ЕСТЬ NULL
ИЛИ КонтактныеЛица.РабМесто = ЗНАЧЕНИЕ(Справочник.РабочиеМеста.ПустаяСсылка)
ТОГДА Сотрудники.РабочееМесто
ИНАЧЕ КонтактныеЛица.РабМесто
КОНЕЦ КАК РабочееМесто
ИЗ
Справочник.ФизическиеЛица КАК ФизическиеЛица
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИТ_КонтактныеЛица КАК КонтактныеЛица
ПО КонтактныеЛица.ФизЛицо = ФизическиеЛица.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Сотрудники
ПО Сотрудники.ФизЛицо = ФизическиеЛица.Ссылка
ГДЕ
ФизическиеЛица.Ссылка = &Ссылка
Такой подход обеспечивает использование первичных индексов СУБД, устраняет необходимость сложных конструкций с условием ИЛИ и гарантирует однозначную подстановку данных.