Как установить отбор по дате для определенного вида документа в запросе с объединением

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

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

Анализ проблемы и типичные ошибки реализации

Разберем типичную ситуацию: разработчик объединяет табличные части документов ВнутреннийЗаказ, ЗаказПоставщику, ПеремещениеТоваров и ПоступлениеТоваровУслуг, помещая результат во временную таблицу ВТ. Далее во второй временной таблице делается попытка отфильтровать поступления с помощью конструкции ВЫБОР КОГДА:


ГДЕ
    ВЫБОР
        КОГДА ВТ.Документ ССЫЛКА Документ.ПоступлениеТоваровУслуг
            ТОГДА ВЫРАЗИТЬ(ВТ.Документ КАК Документ.ПоступлениеТоваровУслуг).Дата МЕЖДУ &Нач И &Кон
        ИНАЧЕ ИСТИНА
    КОНЕЦ

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

  1. Критическое падение производительности («зависание» запроса). Поле Документ во временной таблице имеет составной тип. Обращение через точку к реквизиту Дата заставляет платформу генерировать неявные левые соединения (LEFT JOIN) с таблицами всех типов документов, входящих в составной тип. Поскольку временная таблица не была проиндексирована по полю Документ, СУБД выполняет полное сканирование (Table Scan) в системной базе tempdb. В сочетании со сложным условным оператором в секции ГДЕ это полностью исключает использование индексов по полю Дата.
  2. Ошибки в секции выборки. Попытка вычислить предикат ВЫРАЗИТЬ(...).Дата МЕЖДУ &Нач И &Кон непосредственно в списке полей ВЫБРАТЬ в старых версиях платформы порождает синтаксическую ошибку или неверный SQL-код, так как в большинстве СУБД (включая MS SQL Server) отсутствует полноценный булев тип для столбцов выборки.
  3. Кажущееся отсутствие фильтрации. Объединение ОБЪЕДИНИТЬ ВСЕ собирает независимые строки. Если запрос отобрал сам внутренний заказ, перемещения и заказы поставщикам, а фильтр отсек только строки поступлений, в итоговом результате внутренний заказ все равно останется. Разработчику может ошибочно показаться, что фильтр по дате не сработал вовсе, хотя на самом деле отсеялись только строки поступлений.

Решение 1: Фильтрация на этапе выборки исходных данных (рекомендуемый способ)

Самый правильный и производительный подход с точки зрения архитектуры СУБД — отсекать лишние данные как можно раньше, еще до их попадания во временную таблицу или объединение. Если условие по дате относится исключительно к документу ПоступлениеТоваровУслуг, его необходимо прописать непосредственно в секции ГДЕ той ветки ОБЪЕДИНИТЬ ВСЕ, которая выбирает поступления.

Посмотрим, как выглядит оптимизированный запрос первого этапа:


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

СГРУППИРОВАТЬ ПО
    ВнутреннийЗаказТовары.Ссылка

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

ВЫБРАТЬ
    ЗаказПоставщикуТовары.Заказ,
    ЗаказПоставщикуТовары.Ссылка
ИЗ
    Документ.ЗаказПоставщику.Товары КАК ЗаказПоставщикуТовары
ГДЕ
    ЗаказПоставщикуТовары.Ссылка.ПометкаУдаления = ЛОЖЬ
    И ЗаказПоставщикуТовары.Заказ ССЫЛКА Документ.ВнутреннийЗаказ

СГРУППИРОВАТЬ ПО
    ЗаказПоставщикуТовары.Ссылка,
    ЗаказПоставщикуТовары.Заказ

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

ВЫБРАТЬ
    ПеремещениеТоваровТовары.ВнутреннийЗаказ,
    ПеремещениеТоваровТовары.Ссылка
ИЗ
    Документ.ПеремещениеТоваров.Товары КАК ПеремещениеТоваровТовары
ГДЕ
    ПеремещениеТоваровТовары.Ссылка.ПометкаУдаления = ЛОЖЬ
    И ПеремещениеТоваровТовары.ВнутреннийЗаказ ССЫЛКА Документ.ВнутреннийЗаказ

СГРУППИРОВАТЬ ПО
    ПеремещениеТоваровТовары.Ссылка,
    ПеремещениеТоваровТовары.ВнутреннийЗаказ

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

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

СГРУППИРОВАТЬ ПО
    ПоступлениеТоваровУслугТовары.Заказ,
    ПоступлениеТоваровУслугТовары.Ссылка
;

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

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

Решение 2: Корректная фильтрация по составному полю после объединения

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

Во-первых, временную таблицу необходимо обязательно проиндексировать по составному полю. Во-вторых, вместо громоздкой конструкции ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ИСТИНА КОНЕЦ в секции ГДЕ следует использовать стандартную булеву логику (дизъюнкцию условий):


ВЫБРАТЬ
    ВТ.ВнутреннийЗаказ КАК ВнутреннийЗаказ,
    ВТ.Документ КАК Документ
ПОМЕСТИТЬ ВТ
ИНДЕКСИРОВАТЬ ПО
    Документ
ИЗ
    ... // Блок объединения документов
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.ВнутреннийЗаказ КАК ВнутреннийЗаказ,
    ВТ.Документ КАК Документ
ИЗ
    ВТ КАК ВТ
ГДЕ
    НЕ ВТ.Документ ССЫЛКА Документ.ПоступлениеТоваровУслуг
    ИЛИ (ВЫРАЗИТЬ(ВТ.Документ КАК Документ.ПоступлениеТоваровУслуг).Дата МЕЖДУ &Нач И &Кон)

Такое условие читается СУБД гораздо эффективнее: если документ не является поступлением, вторая часть выражения даже не вычисляется.

Важные нюансы передачи параметров и работы с датами

Проанализируем две распространенные ошибки, из-за которых кажется, что отбор по датам в 1С «не работает»:

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