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

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

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

Анализ проблемы: почему возникают сомнения в выборе периода

Рассмотрим типичную ситуацию. Нам необходимо получить данные из табличной части документа (например, РеализацияТоваровУслуг.Товары) и дополнить их какими-то значениями из регистра сведений (например, ЦеныНоменклатуры). При этом весь отчет строится в рамках двух параметров: &НачалоПериода и &КонецПериода.

Основной вопрос заключается в фильтрации документов. Если мы поставим условие Документ.Дата <= &КонецПериода, мы рискуем получить избыточный объем данных, включая документы за все предыдущие годы существования базы. Если же мы ограничим выборку условием Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода, мы получим только документы текущего интервала. Казалось бы, второй вариант очевиден, но при соединении со срезом последних регистра сведений начинаются сложности в логике данных.

Различие между «состоянием на дату» и «данными за период»

Проанализируем, как работают эти два подхода в контексте виртуальной таблицы СрезПоследних. Важно понимать, что виртуальная таблица СрезПоследних (с параметром &КонецПериода) возвращает актуальное состояние записей на конкретный момент времени. В ней нет понятия «оборотов» или «интервала».

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

Оптимизация производительности: использование временных таблиц

Платформа 1С крайне неэффективно обрабатывает прямые соединения физических таблиц (табличных частей документов) с виртуальными таблицами (срезами регистров). Для оптимизации запроса мы всегда должны использовать временные таблицы. Рассмотрим правильный алгоритм действий.

Шаг 1. Выборка данных из документа во временную таблицу. На этом этапе мы обязательно используем фильтр МЕЖДУ, чтобы ограничить выборку только целевым периодом. Это критически важно для производительности системы.


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

Шаг 2. Индексация. В созданной временной таблице ВТ_Документы необходимо проиндексировать поля, по которым будет происходить соединение (обычно это Номенклатура) и поля, участвующие в логике среза (ДатаДокумента).

Решение задачи получения среза на дату документа

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

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

  1. Сначала получаем максимальные даты записей в регистре, которые не превышают дату документа.
  2. Затем соединяем этот результат с основной таблицей регистра для получения ресурсов (например, цены).

ВЫБРАТЬ
    ВТ.ДокументСсылка,
    ВТ.Номенклатура,
    МАКСИМУМ(Цены.Период) КАК ПериодСреза
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
    ВТ_Документы КАК ВТ
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Цены
        ПО ВТ.Номенклатура = Цены.Номенклатура
            И Цены.Период <= ВТ.ДатаДокумента
СГРУППИРОВАТЬ ПО
    ВТ.ДокументСсылка,
    ВТ.Номенклатура
;

ВЫБРАТЬ
    ВТ_Даты.ДокументСсылка,
    ВТ_Даты.Номенклатура,
    Цены.Цена
ИЗ
    ВТ_МаксимальныеДаты КАК ВТ_Даты
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Цены
        ПО ВТ_Даты.Номенклатура = Цены.Номенклатура
            И ВТ_Даты.ПериодСреза = Цены.Период

Случай, когда документ является регистратором

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

Посмотрим на пример такого соединения:


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

Такой подход будет работать максимально быстро, так как в регистрах поле Регистратор всегда проиндексировано платформой «из коробки».

Подведение итогов по выбору фильтра

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

Помните, что использование условия Документ.Дата <= &КонецПериода без указания начала периода в высоконагруженных базах может привести к критическому замедлению работы сервера СУБД, так как объем обрабатываемых данных будет расти пропорционально возрасту вашей информационной базы.

← На главную