Как в 1С выбрать запросом все заказы, в которых отменены абсолютно все строки?

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

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

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

Метод 1: Использование агрегатной функции МИНИМУМ

Это самый изящный и короткий способ написания запроса. В платформе 1С:Предприятие булево значение Истина при преобразовании в SQL-запрос интерпретируется как 1, а Ложь — как 0. Мы можем использовать это свойство для группировки.

Рассмотрим логику: если в заказе есть хотя бы одна неотмененная строка (Отменено = Ложь), то минимальное значение поля Отменено в группе строк этого заказа будет равно 0 (Ложь). Если же абсолютно все строки имеют значение Истина, то и минимальное значение будет Истина.

Посмотрим на пример реализации такого запроса:


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

Проанализируем этот код. Мы обращаемся к табличной части Товары, группируем записи по полю Ссылка и накладываем условие в секции ИМЕЮЩИЕ. Этот метод отлично подходит для небольших и средних баз данных.

Метод 2: Сравнение количества строк и суммы флагов

Другой подход заключается в математическом сравнении общего количества строк в документе и количества строк, у которых установлен признак отмены. Если эти числа равны, значит, заказ отменен полностью.

Разберем по шагам, как это реализовать в одном запросе:


ВЫБРАТЬ
    ЗаказТовары.Ссылка КАК Ссылка,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказТовары.НомерСтроки) КАК ВсегоСтрок,
    СУММА(ВЫБОР
            КОГДА ЗаказТовары.Отменено
                ТОГДА 1
            ИНАЧЕ 0
        КОНЕЦ) КАК КоличествоОтмененных
ИЗ
    Документ.ЗаказКлиента.Товары КАК ЗаказТовары
СГРУППИРОВАТЬ ПО
    ЗаказТовары.Ссылка
ИМЕЮЩИЕ
    СУММА(ВЫБОР
            КОГДА ЗаказТовары.Отменено
                ТОГДА 1
            ИНАЧЕ 0
        КОНЕЦ) = КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказТовары.НомерСтроки)

Этот метод более нагляден, однако он более громоздкий в написании и требует от СУБД выполнения дополнительных вычислительных операций (суммирования и подсчета количества) для каждой строки табличной части.

Метод 3: Исключение заказов с неотмененными строками (Оптимальный для SQL)

С точки зрения производительности на больших объемах данных (миллионы строк в табличных частях), использование группировки GROUP BY может быть ресурсоемким. Рассмотрим альтернативный метод: выберем все уникальные ссылки заказов, но отсечем те, для которых существует хотя бы одна строка, где Отменено = Ложь.

Этот подход часто называют «методом от противного». Проанализируем пример с использованием оператора НЕ В:


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

Почему это может работать быстрее? В современных СУБД (MS SQL Server, PostgreSQL) оптимизатор запросов может эффективно обработать такие конструкции. Если в табличной части есть индекс по полю Отменено (что встречается редко, но возможно) или по Ссылка, поиск первой же строки со значением Ложь позволит СУБД сразу исключить весь документ из выборки, не сканируя остальные его строки.

Важные технические нюансы и ограничения

При выборе любого из предложенных методов необходимо учитывать специфику работы платформы 1С и бизнес-логику системы.

  1. Проблема пустых табличных частей. Все вышеперечисленные методы работают с таблицей Документ.ЗаказКлиента.Товары. Если в заказе вообще нет строк, он не попадет в выборку. Если по вашей логике пустой заказ также считается «отмененным», вам необходимо начинать запрос от основной таблицы документов Документ.ЗаказКлиента и использовать ЛЕВОЕ СОЕДИНЕНИЕ с таблицей товаров.
  2. Использование секции ИМЕЮЩИЕ vs ГДЕ. Помните, что фильтры по периоду, организации или статусу проведения документа (Проведен) обязательно должны находиться в секции ГДЕ. Если поместить их в ИМЕЮЩИЕ, СУБД сначала сгруппирует все заказы за всю историю существования базы, и только потом отсечет лишние, что приведет к критическому замедлению системы.
  3. Типовые механизмы ERP и УТ 11. В современных конфигурациях (например, 1С:ERP 2.5) разработчики часто добавляют агрегированные статусы в шапку документа. Прежде чем писать сложный запрос по табличным частям, выясните, не меняется ли Статус документа или его реквизит Закрыт при отмене всех строк. Поиск по индексированному полю в шапке всегда в десятки раз быстрее, чем запрос к табличным частям.
  4. Индексация. Поле Отменено в табличных частях обычно не индексируется. Чтобы избежать Full Scan (полного сканирования таблицы), всегда ограничивайте выборку жестким периодом (Дата МЕЖДУ &ДатаНачала И &ДатаКонца).

Итоговые рекомендации

Для повседневных задач и небольших отчетов мы рекомендуем использовать Метод 1 с функцией МИНИМУМ, так как он наиболее прост в поддержке и чтении кода.

Если же вы разрабатываете критически важный узел системы, работающий с огромными массивами данных, рассмотрите Метод 3 или использование временных таблиц для предварительного отбора документов. Это позволит минимизировать нагрузку на сервер БД и обеспечить стабильную работу программы.

← На главную