Как объединить в СКД два запроса с разными периодами дат (прошлый и текущий год)

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

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

Почему обычное соединение запросов (JOIN) работает неправильно

Рассмотрим ситуацию: у нас есть данные по продажам за январь 2023 года и за январь 2024 года. Мы хотим вывести их в одну строку по конкретному менеджеру или покупателю. Если мы попытаемся использовать ЛЕВОЕ СОЕДИНЕНИЕ по полю Покупатель, 1С попытается сопоставить каждую продажу прошлого года с каждой продажей текущего года для этого контрагента. Если в прошлом году было 10 документов, а в текущем — 5, в результате соединения мы можем получить 50 строк. Именно из-за этого итоговые суммы в отчетах становятся неверными.

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

Решение проблемы через объединение (UNION ALL) и временные таблицы

Наиболее надежный и математически точный способ — это собрать данные за прошлый период во временную таблицу, а затем объединить их с данными текущего периода в одном наборе данных. Выясним, как это реализовать по шагам на примере регистра накопления РеализацияТМЗ.

Шаг 1. Формируем данные за прошлый период

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


ВЫБРАТЬ
    НАЧАЛОПЕРИОДА(РеализацияТМЗОбороты.Период, МЕСЯЦ) КАК Период,
    РеализацияТМЗОбороты.ДоговорКонтрагента.Владелец.ОсновнойМенеджерПокупателя КАК Покупатель,
    РеализацияТМЗОбороты.СуммаОборот КАК СуммаОборотПрошл
ПОМЕСТИТЬ ДанныеПрошлогоГода
ИЗ
    РегистрНакопления.РеализацияТМЗ.Обороты({(&НачалоПериода1)}, {(&КонецПериода1)}, Регистратор, ) КАК РеализацияТМЗОбороты
;

Шаг 2. Основной запрос с объединением

Теперь мы выбираем данные текущего года и добавляем к ним данные из нашей временной таблицы. Чтобы СКД могла сопоставить данные прошлого года с текущим в одной строке (например, в кросс-таблице), мы используем функцию ДОБАВИТЬКДАТЕ, «сдвигая» даты прошлого года на один год вперед.


// Выбираем данные текущего периода
ВЫБРАТЬ
    НАЧАЛОПЕРИОДА(РеализацияТМЗОбороты.Период, МЕСЯЦ) КАК Период,
    РеализацияТМЗОбороты.ДоговорКонтрагента.Владелец.ОсновнойМенеджерПокупателя КАК Покупатель,
    0 КАК СуммаОборотПрошл,
    РеализацияТМЗОбороты.СуммаОборот КАК СуммаОборотТек
ИЗ
    РегистрНакопления.РеализацияТМЗ.Обороты(, , Регистратор, ) КАК РеализацияТМЗОбороты

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

// Примешиваем данные прошлого года, сдвигая период
ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(ДанныеПрошлогоГода.Период, ГОД, 1),
    ДанныеПрошлогоГода.Покупатель,
    ДанныеПрошлогоГода.СуммаОборотПрошл,
    0 КАК СуммаОборотТек
ИЗ
    ДанныеПрошлогоГода КАК ДанныеПрошлогоГода

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

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

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

Посмотрим на пример логики в запросе:


ВЫБРАТЬ
    // Приводим все даты к текущему году для сопоставления
    ВЫБОР 
        КОГДА РеализацияТМЗОбороты.Период < &НачалоТекущегоПериода 
        ТОГДА ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(РеализацияТМЗОбороты.Период, МЕСЯЦ), ГОД, 1)
        ИНАЧЕ НАЧАЛОПЕРИОДА(РеализацияТМЗОбороты.Период, МЕСЯЦ) 
    КОНЕЦ КАК ПериодДляСравнения,
    
    Покупатель,
    
    // Суммируем в разные колонки в зависимости от года
    ВЫБОР 
        КОГДА РеализацияТМЗОбороты.Период < &НачалоТекущегоПериода ТОГДА СуммаОборот ИНАЧЕ 0 
    КОНЕЦ КАК СуммаПрошлыйГод,
    
    ВЫБОР 
        КОГДА РеализацияТМЗОбороты.Период >= &НачалоТекущегоПериода ТОГДА СуммаОборот ИНАЧЕ 0 
    КОНЕЦ КАК СуммаТекущийГод
ИЗ
    РегистрНакопления.РеализацияТМЗ.Обороты(&НачалоПрошлогоГода, &КонецТекущегоГода, , )

Важные настройки в СКД

Чтобы отчет работал безупречно, обратим внимание на следующие настройки компоновки:

  1. Роли полей: Для поля Период в схеме компоновки данных обязательно укажите роль «Период». Это позволит СКД корректно обрабатывать временные интервалы.
  2. Параметры: Если вы используете вложенные запросы или виртуальные таблицы с параметрами, убедитесь, что в настройках параметров на закладке «Параметры» СКД для дат начала и конца периода установлена галочка «Запрещать незаполненные значения». Это предотвратит попытки системы получить данные за «пустой» период, что может вызвать ошибку СУБД.
  3. Вычисляемые поля: Если вам нужно вычислять процент отклонения (например, насколько продажи текущего года больше прошлого), делайте это на закладке «Вычисляемые поля» или в ресурсах, используя формулу: (Сумма(СуммаОборотТек) - Сумма(СуммаОборотПрошл)) / Сумма(СуммаОборотПрошл) * 100.

Проанализировав эти методы, можно сделать вывод, что использование ОБЪЕДИНИТЬ ВСЕ является наиболее прозрачным и простым способом для сравнения периодов «год к году». Это гарантирует отсутствие дублей и позволяет легко выводить данные в кросс-таблицы, где колонками будут выступать месяцы, а внутри каждой ячейки — показатели двух разных лет.

← На главную