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

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

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

Метод 1. Использование левого соединения и проверки на NULL

Это самый популярный и классический метод, который упоминается в сообщениях форума. Разберем его логику. Мы выбираем основную таблицу документов и «приклеиваем» к ней таблицу её же табличной части с помощью ЛЕВОГО СОЕДИНЕНИЯ. Если в табличной части нет записей для конкретного документа, то во всех полях присоединенной таблицы для этого документа будет стоять значение NULL.

Рассмотрим пример запроса, предложенный в сообщении №9:


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

Проанализируем этот код. Мы связываем документ с его ТЧ по полю Ссылка. Условие ГДЕ ТЧ.Ссылка ЕСТЬ NULL отсекает все документы, у которых нашлась хотя бы одна строка в табличной части. В итоге в выборку попадут только те документы, для которых в ТЧ не найдено ни одной записи.

Важный нюанс: при использовании этого метода следует быть осторожным, если вы выбираете дополнительные данные из других табличных частей. Левое соединение может привести к дублированию строк в результате запроса (картезианское произведение), если не использовать группировку или ключевое слово РАЗЛИЧНЫЕ. Однако, если ваша задача — просто получить список ссылок на пустые документы, этот метод работает отлично.

Метод 2. Использование конструкции НЕ СУЩЕСТВУЕТ (NOT EXISTS)

Этот способ часто считается более «чистым» и производительным с точки зрения СУБД. Конструкция ГДЕ НЕ СУЩЕСТВУЕТ позволяет проверить отсутствие записей в связанной таблице без необходимости физического соединения всех строк. СУБД прекращает поиск в табличной части, как только находит первую подходящую строку, что экономит ресурсы.

Разберем, как написать такой запрос:


ВЫБРАТЬ
    План.Ссылка
ИЗ
    Документ.агПланКомандировки КАК План
ГДЕ
    НЕ СУЩЕСТВУЕТ (
        ВЫБРАТЬ
            1
        ИЗ
            Документ.агПланКомандировки.БюджетКомандировки КАК Бюджет
        ГДЕ
            Бюджет.Ссылка = План.Ссылка
    )

В данном случае мы используем вложенный запрос. Если вложенный запрос возвращает хотя бы одну строку (то есть СУЩЕСТВУЕТ), то основной документ исключается из результата благодаря оператору НЕ. Это решение исключает проблему дублирования строк, о которой мы говорили в первом методе.

Метод 3. Отрицание вхождения через НЕ В (NOT IN)

Еще один наглядный способ — выбрать все документы, чья ссылка НЕ Встречается в списке ссылок таблицы этой табличной части. Рассмотрим пример:


ВЫБРАТЬ
    Реализация.Ссылка
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Ссылка НЕ В (
        ВЫБРАТЬ
            ТЧ.Ссылка
        ИЗ
            Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
    )

Проанализируем ситуацию: вложенный запрос выбирает вообще все ссылки документов, у которых есть хотя бы одна строка в таблице Товары. Основной запрос берет все документы и оставляет только те, которых нет в этом «черном списке».

Особенности метода: на очень больших таблицах (сотни тысяч или миллионы строк) оператор НЕ В может работать медленнее, чем НЕ СУЩЕСТВУЕТ или ЛЕВОЕ СОЕДИНЕНИЕ, так как СУБД иногда неэффективно строит план выполнения для таких условий. Однако для большинства повседневных задач этот метод наиболее читаем.

Метод 4. Использование временных таблиц

Иногда, как показано в сообщении №8, разработчики предпочитают сначала выгрузить данные во временную таблицу. Это оправдано, если далее в этом же запросе вам нужно будет многократно использовать информацию о «пустоте» документа для сложных расчетов.

Посмотрим на логику шагов:

  1. Создаем временную таблицу, в которой соединяем документы с ТЧ.
  2. Для проверки используем функцию ЕСТЬNULL, заменяя отсутствующее значение на флаг (например, ЛОЖЬ).
  3. В следующем пакете запроса выбираем данные из временной таблицы по этому флагу.

Хотя для простой задачи это кажется избыточным, в сложных отчетах СКД такой подход помогает оптимизировать работу с индексами временных таблиц.

Распространенная ошибка: Использование Количество()

Выясним причину, почему предложения из сообщений №5 и №6 (ТЧ.Количество = 0) не работают в запросах. В языке 1С есть два контекста: объектная модель и язык запросов. В объектной модели (код в модулях) мы действительно можем написать Если Объект.Товары.Количество() = 0 Тогда....

Однако запрос обращается напрямую к таблицам базы данных. В базе данных нет такого поля, как «Количество строк». Каждая строка табличной части — это отдельная запись в физической таблице. Если строк нет, то в таблице просто отсутствуют записи с соответствующим Ref (Ссылкой). Поэтому агрегатная функция КОЛИЧЕСТВО() внутри запроса выдаст результат только в том случае, если вы сгруппируете данные. Но если записей нет совсем, группировка их просто проигнорирует, и вы получите пустой результат вместо заветного «0».

Сводная таблица методов

Рассмотрим краткие рекомендации по выбору метода:

  1. ЛЕВОЕ СОЕДИНЕНИЕ + NULL: Оптимально для простых выборок, где нужно быстро получить результат и вы уверены, что строки не будут множиться.
  2. НЕ СУЩЕСТВУЕТ: Лучший выбор с точки зрения производительности и чистоты кода. Рекомендуется для использования в тиражных решениях.
  3. НЕ В: Самый понятный код для быстрого написания разовых обработок.

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

← На главную