Как в запросе 1С найти заказы, входящие ровно в два маршрутных листа

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

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

Анализ проблемы и типичной ошибки группировки

Рассмотрим ситуацию, с которой столкнулся автор темы. Изначально была попытка выбрать данные из табличной части Заказы документа МаршрутныйЛист. Основная сложность заключалась в том, что при стандартном подходе запрос выводит все пары «Маршрутный лист — Заказ», не ограничивая выборку по количеству вхождений.

Разберем типичную ошибку, которую часто допускают при использовании предложения СГРУППИРОВАТЬ ПО. Если мы группируем результат одновременно и по заказу, и по маршрутному листу, то каждая строка в результате запроса всегда будет уникальной. В этом случае агрегатная функция КОЛИЧЕСТВО всегда вернет единицу, так как внутри группы «Заказ №1 + Маршрутный лист №1» существует только одна запись. Для решения нашей задачи нам необходимо изменить логику группировки.

Решение 1: Использование предложения ИМЕЮЩИЕ (HAVING)

Самый простой и быстрый способ отобрать нужные данные — это сгруппировать записи только по полю Заказ и применить фильтр к результату выполнения агрегатной функции. Давайте посмотрим на пример такого кода:


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

Проанализируем этот запрос подробнее:

  1. Мы используем конструкцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...). Это критически важно, если один и тот же заказ может быть по ошибке добавлен в один и тот же маршрутный лист дважды. В таком случае обычный счетчик выдаст 2, хотя документа фактически два разных не будет.
  2. Группировка идет только по полю Заказ. Это позволяет «схлопнуть» все упоминания заказа во всех документах в одну строку для анализа.
  3. Секция ИМЕЮЩИЕ (аналог HAVING в SQL) отсекает все заказы, которые встречаются в базе чаще или реже двух раз за указанный период.

Решение 2: Использование временных таблиц (Best Practice)

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

Разберем этот метод по шагам:

Шаг 1: Отбираем список заказов-дублей во временную таблицу.


ВЫБРАТЬ
    МаршрутныйЛистЗаказы.Заказ КАК Заказ
ПОМЕСТИТЬ ВТ_ЗаказыДубли
ИЗ
    Документ.МаршрутныйЛист.Заказы КАК МаршрутныйЛистЗаказы
СГРУППИРОВАТЬ ПО
    МаршрутныйЛистЗаказы.Заказ
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ МаршрутныйЛистЗаказы.Ссылка) = 2
;

Шаг 2: Соединяем временную таблицу с исходными данными для получения полной информации.


ВЫБРАТЬ
    МаршрутныйЛистЗаказы.Ссылка КАК Маршрутник,
    МаршрутныйЛистЗаказы.Заказ КАК Заказ
ИЗ
    ВТ_ЗаказыДубли КАК ЗаказыДубли
ВНУТРЕННЕЕ СОЕДИНЕНИЕ 
    Документ.МаршрутныйЛист.Заказы КАК МаршрутныйЛистЗаказы
ПО 
    ЗаказыДубли.Заказ = МаршрутныйЛистЗаказы.Заказ
АВТОУПОРЯДОЧИВАНИЕ

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

Решение 3: Метод самосоединения (Self-Join)

Рассмотрим еще один интересный способ, который упоминался в обсуждении на форуме — это соединение таблицы самой с собой. Этот метод полезен, когда нужно сравнить значения полей в двух разных вхождениях одного и того же объекта.


ВЫБРАТЬ
    Лист1.Заказ КАК Заказ,
    Лист1.Ссылка КАК Маршрутник1,
    Лист2.Ссылка КАК Маршрутник2
ИЗ
    Документ.МаршрутныйЛист.Заказы КАК Лист1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ 
    Документ.МаршрутныйЛист.Заказы КАК Лист2 
ПО 
    Лист1.Заказ = Лист2.Заказ 
    И Лист1.Ссылка <> Лист2.Ссылка

Выясним причину, по которой этот метод стоит использовать с осторожностью. Если заказ входит в три документа, такой запрос создаст избыточное количество комбинаций строк. Однако для поиска именно «парных» документов это может быть наглядным решением. Главное условие здесь — Лист1.Ссылка <> Лист2.Ссылка, которое гарантирует, что мы нашли разные документы с одинаковым содержанием.

Важные рекомендации по производительности

При работе с большими объемами данных в 1С (например, если документов МаршрутныйЛист за год накапливаются десятки тысяч), следует учитывать несколько аспектов:

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

← На главную