Как в запросе СКД получить данные за два месяца (текущий и следующий) на основе выбранной даты

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

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

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

Метод 1. Использование выражений параметров СКД

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

Рассмотрим по шагам, как это настроить:

  1. Добавим параметр ДатаНачала (тип Дата), который будет выбирать пользователь.
  2. Добавим параметр КонецПериодаОтчета. Сделаем его доступным только для системы (снимем галочку "Включать в пользовательские настройки").
  3. В поле "Выражение" для КонецПериодаОтчета пропишем: КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаНачала, "Месяц", 1), "Месяц").

Таким образом, если пользователь выберет 01.09.2023, система автоматически рассчитает конец следующего месяца — 31.10.2023. В тексте запроса нам останется только использовать условие:


ГДЕ
    ПоступлениеТовара.Дата МЕЖДУ &ДатаНачала И &КонецПериодаОтчета
    И ПоступлениеТовара.Проведен = ИСТИНА

Метод 2. Соединение табличных частей документов

Проанализируем ситуацию, когда данные плана и факта хранятся в разных документах, например, ПланыОбъемовПоПродажам и ПоступлениеТовара. При прямом левом соединении табличных частей важно учитывать риск "размножения" строк.

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


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

Важный нюанс: Чтобы избежать дублирования сумм, рекомендуется предварительно сгруппировать данные в каждой таблице. Выясним, как это сделать правильно в следующем методе.

Метод 3. Оптимизация через временные таблицы

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

Рассмотрим структуру такого запроса:


// Помещаем данные плана во временную таблицу
ВЫБРАТЬ
    Планы.Товар КАК Товар,
    СУММА(Планы.Количество) КАК КоличествоПлан
ПОМЕСТИТЬ ВТ_План
ИЗ
    Документ.ПланыОбъемовПоПродажам.Товары КАК Планы
ГДЕ
    Планы.Ссылка.Дата МЕЖДУ &ДатаНачала И &КонецПериодаОтчета
    И Планы.Ссылка.Проведен
СГРУППИРОВАТЬ ПО
    Планы.Товар;

////////////////////////////////////////////////////////////////////////////////
// Помещаем данные факта во временную таблицу
ВЫБРАТЬ
    Факт.Товар КАК Товар,
    СУММА(Факт.Количество) КАК КоличествоФакт
ПОМЕСТИТЬ ВТ_Факт
ИЗ
    Документ.ПоступлениеТовара.Товары КАК Факт
ГДЕ
    Факт.Ссылка.Дата МЕЖДУ &ДатаНачала И &КонецПериодаОтчета
    И Факт.Ссылка.Проведен
СГРУППИРОВАТЬ ПО
    Факт.Товар;

////////////////////////////////////////////////////////////////////////////////
// Соединяем подготовленные данные
ВЫБРАТЬ
    ЕСТЬNULL(ВТ_План.Товар, ВТ_Факт.Товар) КАК Товар,
    ЕСТЬNULL(ВТ_План.КоличествоПлан, 0) КАК КоличествоПлан,
    ЕСТЬNULL(ВТ_Факт.КоличествоФакт, 0) КАК КоличествоФакт
ИЗ
    ВТ_План КАК ВТ_План
        ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Факт КАК ВТ_Факт
        ПО ВТ_План.Товар = ВТ_Факт.Товар

При использовании ПОЛНОЕ СОЕДИНЕНИЕ мы не потеряем данные, если план есть, а факта нет, или наоборот.

Метод 4. Использование "ОБЪЕДИНИТЬ ВСЕ" для задач План-Факт

Существует еще более надежный архитектурный подход для СКД — использование оператора ОБЪЕДИНИТЬ ВСЕ. Этот метод позволяет избежать проблем со сложными условиями соединений и работает быстрее на больших объемах данных.

Проанализируем логику этого подхода:

  1. Первым запросом выбираем плановые данные, устанавливая КоличествоФакт в 0.
  2. Вторым запросом выбираем фактические данные, устанавливая КоличествоПлан в 0.
  3. В СКД настраиваем ресурсы для полей количества (функция Сумма).

Пример реализации:


ВЫБРАТЬ
    Планы.Товар КАК Товар,
    НАЧАЛОПЕРИОДА(Планы.Ссылка.Дата, МЕСЯЦ) КАК Период,
    Планы.Количество КАК КоличествоПлан,
    0 КАК КоличествоФакт
ИЗ
    Документ.ПланыОбъемовПоПродажам.Товары КАК Планы
ГДЕ
    Планы.Ссылка.Дата МЕЖДУ &ДатаНачала И &КонецПериодаОтчета

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

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

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

Дополнительные возможности СКД для работы с периодами

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

Чтобы пустые месяцы не пропадали из отчета (например, если во втором месяце не было ни плана, ни факта, но мы хотим видеть нулевую колонку), воспользуемся механизмом дополнения периодов:

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

← На главную