Как в СКД задать динамическое начало периода для каждого договора?

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

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

В этой статье мы подробно разберем, как реализовать динамическое начало периода, проанализируем различные подходы и выберем оптимальный в зависимости от объема данных и требований к производительности.

Метод 1. Связь наборов данных через параметры (Рекомендуемый)

Этот способ считается наиболее элегантным и «правильным» с точки зрения архитектуры СКД. Он позволяет передавать значение из одной выборки в качестве параметра для другой. Разберем этот процесс по шагам.

Во-первых, нам необходимо создать два отдельных набора данных — запроса.

Набор данных 1 (Договоры): Здесь мы получаем основной список объектов и их даты заключения.


ВЫБРАТЬ
    ДоговорыКонтрагентов.Ссылка КАК Договор,
    ДоговорыКонтрагентов.Дата КАК ДатаЗаключения
ИЗ
    Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
ГДЕ
    ДоговорыКонтрагентов.Ссылка В (&СписокДоговоров)

Набор данных 2 (Обороты): Обращаемся к виртуальной таблице оборотов. Обратите внимание, что в тексте запроса мы используем стандартный параметр &НачалоПериода.


ВЫБРАТЬ
    ПродажиОбороты.ДоговорКонтрагента КАК Договор,
    ПродажиОбороты.КоличествоОборот КАК КоличествоОборот,
    ПродажиОбороты.СтоимостьОборот КАК СтоимостьОборот
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты

Во-вторых, переходим на закладку «Связи наборов данных». Здесь происходит «магия»:

  1. В поле «Источник связи» указываем Набор1.
  2. В поле «Приемник связи» указываем Набор2.
  3. Условие связи: Договор = Договор.
  4. В колонке «Параметры связи» для параметра НачалоПериода указываем выражение ДатаЗаключения.

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

Метод 2. Фильтрация по полю Период в виртуальной таблице

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

Если в виртуальной таблице Обороты не выбрано поле периода, система выдаст агрегированный результат за весь интервал. Чтобы отсечь лишние данные, нам нужно добавить периодичность в запрос.

Проанализируем пример запроса:


ВЫБРАТЬ
    ПродажиОбороты.ДоговорКонтрагента,
    ПродажиОбороты.Период КАК ПериодДвижения,
    ПродажиОбороты.КоличествоОборот,
    ПродажиОбороты.СтоимостьОборот
ИЗ
    РегистрНакопления.Продажи.Обороты(, &КонецПериода, День, ) КАК ПродажиОбороты
ГДЕ
    ПродажиОбороты.Период >= ПродажиОбороты.ДоговорКонтрагента.Дата

В данном случае мы устанавливаем НачалоПериода в значение «Не определено» (пустая дата), но за счет условия ГДЕ и выбранного поля Период, система корректно отфильтрует движения. Главный минус этого метода — потенциальное снижение производительности, так как системе приходится считывать данные за весь период существования регистра перед фильтрацией.

Метод 3. Использование физической таблицы регистра

Когда объемы данных исчисляются миллионами строк, а обращение к виртуальным таблицам становится неэффективным из-за сложных условий, мы можем обратиться к «физике» (таблице движений).

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

Рассмотрим структуру запроса к физической таблице:


ВЫБРАТЬ
    Продажи.ДоговорКонтрагента КАК Договор,
    СУММА(Продажи.Количество) КАК КоличествоОборот,
    СУММА(Продажи.Стоимость) КАК СтоимостьОборот
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    Продажи.Период >= Продажи.ДоговорКонтрагента.Дата
    И Продажи.Период <= &КонецПериода
СГРУППИРОВАТЬ ПО
    Продажи.ДоговорКонтрагента

Преимущества:

Недостатки:

Метод 4. Вычисляемые поля и внешние функции

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

В СКД на закладке «Вычисляемые поля» можно добавить поле, значение которого будет вычисляться так:

МойОбщийМодуль.ОпределитьДатуНачала(Договор)

Однако помните: это самый медленный способ. Мы рекомендуем использовать его только в тех случаях, когда количество строк в итоговом отчете невелико (десятки или сотни), иначе формирование отчета может затянуться на длительное время.

Особенности работы с итогами и иерархией

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

Чтобы итоги в СКД рассчитывались корректно, используйте ресурсы с правильными выражениями. Рекомендуется явно указывать агрегатные функции в настройках ресурсов:

СУММА(КоличествоОборот)

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

← На главную