Как в 1С отобрать документы, по которым отсутствуют подчиненные документы?

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

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

Разберем подробно, как правильно составить такой запрос на языке запросов 1С, выясним причины типичных ошибок при отборе по значению NULL и рассмотрим альтернативные подходы.

Способ 1. Левое соединение с проверкой на ЕСТЬ NULL (классический и рекомендуемый подход)

Наиболее производительным и стандартным способом является использование конструкции ЛЕВОЕ СОЕДИНЕНИЕ с последующей проверкой ключевого реквизита присоединенной таблицы на ЕСТЬ NULL.

Рассмотрим логику работы:

  1. В качестве основной таблицы выбираем таблицу родительских документов (например, Документ.бит_РегистрацияДоговоровАренды).
  2. Выполняем левое соединение с подчиненной таблицей (например, Документ.бит_РасторжениеДоговора) по полю связи — как правило, это реквизит Основание или ДокументОснование в подчиненном документе.
  3. Для тех родительских документов, у которых подчиненный документ отсутствует, все поля правой таблицы в результирующей выборке заполняются системным значением NULL.
  4. В секции ГДЕ накладываем условие ПолеПодчиненногоДокумента ЕСТЬ NULL.

Посмотрим на пример запроса:


ВЫБРАТЬ
    Регистрация.Ссылка КАК ДокументОснование
ИЗ
    Документ.бит_РегистрацияДоговоровАренды КАК Регистрация
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.бит_РасторжениеДоговора КАК Расторжение
        ПО Регистрация.Ссылка = Расторжение.Основание
ГДЕ
    Расторжение.Ссылка ЕСТЬ NULL

В блоке ГДЕ в качестве проверяемого поля рекомендуется указывать либо само поле связи (Расторжение.Основание), либо первичный ключ присоединенной таблицы (Расторжение.Ссылка).

Разбор типичных ошибок: почему не работают проверки с ПустаяСсылка и НЕ ... ССЫЛКА

Проанализируем частые ошибки разработчиков, которые приводят либо к получению пустой выборки, либо к выводу всех документов без фильтрации:

  1. Сравнение с пустой ссылкой: Попытка написать условие вида ГДЕ НЕ Расторжение.Ссылка = Значение(Документ.бит_РасторжениеДоговора.ПустаяСсылка). При левом соединении для отсутствующих записей формируется значение NULL, а не пустая ссылка конфигурации. В реляционной логике SQL любое равенство со значением NULL возвращает неопределенный результат (UNKNOWN), а отрицание НЕ (UNKNOWN) также дает UNKNOWN. В результате блок ГДЕ отсекает абсолютно все строки.
  2. Использование оператора ССЫЛКА с отрицанием: Конструкция ГДЕ НЕ Расторжение.Ссылка ССЫЛКА Документ.бит_РасторжениеДоговора также ведет себя некорректно при трансляции в SQL-запрос для значений NULL и не должна использоваться для проверки физического отсутствия записи.

Запомним главное правило: для проверки отсутствия присоединенной записи в языке запросов 1С используется исключительно оператор ЕСТЬ NULL.

Способ 2. Использование подзапроса с конструкцией НЕ В

Другим наглядным вариантом решения является отбор с использованием отрицания вхождения во вложенный список.

Посмотрим на реализацию:


ВЫБРАТЬ
    ДокРегистрация.Ссылка КАК Ссылка
ИЗ
    Документ.бит_РегистрацияДоговоровАренды КАК ДокРегистрация
ГДЕ
    ДокРегистрация.Ссылка НЕ В
        (ВЫБРАТЬ
            ДокРасторжение.Основание КАК Основание
        ИЗ
            Документ.бит_РасторжениеДоговора КАК ДокРасторжение
        ГДЕ
            ДокРасторжение.Основание ЕСТЬ НЕ NULL)

Обратим внимание на важную деталь: во вложенном запросе обязательно должно присутствовать условие ГДЕ ДокРасторжение.Основание ЕСТЬ НЕ NULL. Если во вложенную выборку попадет хотя бы одно значение NULL, предикат NOT IN в SQL вернет пустой результат для всего запроса.

Важные нюансы: статус проведения, пометка удаления и дублирование строк

При построении запросов к реальным базам данных необходимо учитывать следующие практические особенности:

  1. Учет статуса подчиненного документа: Если документ расторжения был создан, но помечен на удаление или не проведен, стандартное соединение все равно сопоставит его с договором. Чтобы считать договор расторгнутым только при наличии проведенного документа, условия накладываются непосредственно в секции ПО:
    
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.бит_РасторжениеДоговора КАК Расторжение
        ПО Регистрация.Ссылка = Расторжение.Основание
        И Расторжение.Проведен = ИСТИНА
        И Расторжение.ПометкаУдаления = ЛОЖЬ
    
  2. Дублирование строк при множественных подчиненных документах: Если на один договор по ошибке пользователя введено несколько документов расторжения, обычное левое соединение размножит строки родительского документа в выборке. Чтобы этого избежать, используйте ключевое слово ВЫБРАТЬ РАЗЛИЧНЫЕ или выполняйте группировку СГРУППИРОВАТЬ ПО.

Альтернативный вариант: проверка через Критерии отбора в коде

Если требуется проверить наличие подчиненных документов не для массового отчета, а для одного конкретного документа в модуле объекта или формы, можно воспользоваться объектом конфигурации КритерииОтбора:


МассивПодчиненных = КритерииОтбора.СвязанныеДокументы.Найти(СсылкаНаДоговор);
Если МассивПодчиненных.Количество() = 0 Тогда
    // Подчиненные документы отсутствуют
КонецЕсли;

Этот метод позволяет быстро получить связанные данные по структуре подчиненности без написания ручных запросов.

← На главную