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