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

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Особенности структуры метаданных 1С и механизм связей

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

Механизм КритерийОтбора (такой как СвязанныеДокументы или СтруктураПодчиненности) удобен для интерактивного отображения цепочек по одному объекту, но не предназначен для массовой обработки больших списков в запросах. Поэтому для получения документов без подчиненных мы используем конструкцию ЛЕВОЕ СОЕДИНЕНИЕ с проверкой на значение NULL.

Базовый вариант: поиск отсутствия одного типа подчиненного документа

Разберем классическую логику левого внешнего соединения. При левом соединении в результирующую выборку попадают все строки из левой таблицы. Если в правой таблице не найдено соответствия по условию связи, поля правой таблицы заполняются значениями NULL.

Проанализируем распространенную ошибку: если разместить условие Реализация.Ссылка ЕСТЬ NULL внутри секции ПО (в условии соединения), запрос отработает некорректно. Проверка отсутствия связанных строк должна находиться исключительно в секции ГДЕ.

Посмотрим на пример правильного запроса с отбором счетов за период, по которым нет ни одной реализации:


ВЫБРАТЬ
    Счет.Ссылка КАК Документ
ИЗ
    Документ.СчетНаОплатуПокупателю КАК Счет
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
        ПО Счет.Ссылка = Реализация.Сделка
ГДЕ
    Счет.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И Реализация.Ссылка ЕСТЬ NULL

Разберем по шагам ключевые моменты этого запроса:

  1. Секция ПО: связывает счет с реализацией по ссылке на документ-основание. Здесь не должно быть ограничения на дату счета или дату реализации, иначе логика соединения нарушится.
  2. Секция ГДЕ: фильтрует исходные счета по нужному интервалу дат (Счет.Дата МЕЖДУ &НачалоПериода И &КонецПериода) и оставляет только те строки, где соединение не нашло соответствий (Реализация.Ссылка ЕСТЬ NULL).

Важный нюанс: фильтрация дат подчиненных документов

Проанализируем частую логическую ошибку: нельзя накладывать условие на период подчиненного документа (например, Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода). Если счет был выписан в конце месяца, а реализация создана в начале следующего месяца за рамками периода, такой счет будет ошибочно распознан как «не имеющий подчиненных документов». Подчиненный документ должен проверяться на всем интервале времени после даты счета.

Оптимальное решение для нескольких видов подчиненных документов

На практике на основании счета могут вводиться не только реализации, но и кассовые ордера (ПриходныйКассовыйОрдер), банковские выписки (ПлатежноеПоручениеВходящее) и другие документы. Кроме того, реквизит Сделка или ДокументОснование часто имеет составной тип данных.

Если соединять таблицы напрямую через составной тип без типизации, СУБД выполнит неявные соединения со всеми возможными таблицами, что вызовет сильные задержки. Для максимальной производительности используем пакетный запрос с индексированной временной таблицей и явным приведением типов через ВЫРАЗИТЬ.

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


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

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ВЫРАЗИТЬ(Платежка.ДокументОснование КАК Документ.СчетНаОплатуПокупателю)
ИЗ
    Документ.ПлатежноеПоручениеВходящее КАК Платежка
ГДЕ
    НЕ Платежка.ПометкаУдаления
    И Платежка.ДокументОснование ССЫЛКА Документ.СчетНаОплатуПокупателю

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ВЫРАЗИТЬ(ПКО.ДокументОснование КАК Документ.СчетНаОплатуПокупателю)
ИЗ
    Документ.ПриходныйКассовыйОрдер КАК ПКО
ГДЕ
    НЕ ПКО.ПометкаУдаления
    И ПКО.ДокументОснование ССЫЛКА Документ.СчетНаОплатуПокупателю

ИНДЕКСИРОВАТЬ ПО
    ДокументОснование
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Счет.Ссылка КАК СчетНаОплату,
    Счет.Номер КАК Номер,
    Счет.Дата КАК Дата,
    Счет.Контрагент КАК Контрагент,
    Счет.СуммаДокумента КАК Сумма
ИЗ
    Документ.СчетНаОплатуПокупателю КАК Счет
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Подчиненные КАК Подчиненные
        ПО Счет.Ссылка = Подчиненные.ДокументОснование
ГДЕ
    Счет.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И НЕ Счет.ПометкаУдаления
    И Подчиненные.ДокументОснование ЕСТЬ NULL

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

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

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