Как настроить отбор по периоду и корректно соединить данные из регистров сведений и накопления в отчете СКД

Программист Управленческий учет IT и автоматизация бизнеса
← На главную

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

Проблема: Почему выводятся лишние данные?

Рассмотрим типичную ситуацию: у нас есть регистр сведений НормаМесяц (где хранится норма часов для каждого сотрудника на каждый месяц) и оборотный регистр накопления Выработка (где фиксируется реальный результат). Если просто перечислить эти таблицы в запросе через запятую, 1С попытается выполнить перекрестное соединение (Cartesian product), либо, если соединение указано неверно, привяжет каждую запись о норме к каждой записи о факте.

Основные причины «неработающего» отбора:

  1. Отсутствие параметров в виртуальных таблицах: Виртуальная таблица Обороты без указания параметров выбирает данные за все время существования базы.
  2. Отсутствие связи по измерениям: В запросе не указано, что сотрудник из регистра сведений — это тот же самый сотрудник, что и в регистре накопления.
  3. Разрыв связи по периоду: Регистр сведений может хранить записи на начало месяца (например, 01.01.2023), а отчет формируется за произвольный интервал. Без явного указания связи по периоду система не поймет, какую именно норму подтянуть к факту.

Шаг 1: Настройка параметров виртуальных таблиц

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


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

Здесь &НачалоПериода и &КонецПериода — это стандартные параметры СКД. Если их не указать внутри скобок, СКД попытается наложить отбор позже, через секцию ГДЕ, что крайне неэффективно и часто приводит к ошибкам в расчете остатков и оборотов.

Шаг 2: Правильное соединение таблиц

Теперь рассмотрим ситуацию, когда нам нужно добавить норму выработки. Нам необходимо соединить данные из регистра накопления с регистром сведений. Важно использовать ЛЕВОЕ СОЕДИНЕНИЕ, чтобы в отчет попали даже те сотрудники, по которым есть факт выработки, но по какой-то причине не внесена норма.

Проанализируем правильную структуру соединения:


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

Обратите внимание на использование функции ЕСТЬNULL. Если в регистре сведений не окажется записи для конкретного сотрудника, система вернет NULL. Математические операции с NULL всегда дают NULL, поэтому для расчета отклонений (Факт - Норма) нам необходимо преобразовать пустоту в ноль.

Шаг 3: Синхронизация периодов в запросе

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

Рассмотрим два способа решения:

  1. Использование СрезаПоследних: Если норма устанавливается один раз и действует до следующего изменения, лучше использовать виртуальную таблицу СрезПоследних(&КонецПериода).
  2. Фильтрация физической таблицы: Если нормы вводятся строго помесячно, в секции ГДЕ или в условии соединения нужно ограничить период регистра сведений:

ГДЕ
    Нормы.Период МЕЖДУ &НачалоПериода И &КонецПериода

Однако помните, что если в СКД выбран период "Сентябрь", то &НачалоПериода будет 01.09.2023 00:00:00, а &КонецПериода — 30.09.2023 23:59:59. Если норма в регистре записана датой 01.09.2023 00:00:00, отбор сработает корректно.

Шаг 4: Настройка параметров в СКД (вкладка "Параметры")

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

Таким образом, пользователь выбирает понятный интервал (например, "Прошлый месяц"), а технические параметры, используемые в запросе, заполняются автоматически.

Шаг 5: Профессиональный подход — Связи наборов данных

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

1. Создаем НаборДанных1 (Запрос) к регистру накопления (Факт).

2. Создаем НаборДанных2 (Запрос) к регистру сведений (Норма).

3. Переходим на вкладку "Связи наборов данных".

Здесь мы указываем "Источник связи" (Факт) и "Приемник" (Норма). В условиях связи указываем Сотрудник = Сотрудник. Это позволяет СКД более интеллектуально управлять выборкой, особенно если один из регистров содержит гораздо больше измерений, чем другой.

Важный нюанс: Чтобы связь по периоду работала в этом случае, в обоих наборах данных должно быть поле Период, приведенное к единому формату (например, через НАЧАЛОПЕРИОДА(..., МЕСЯЦ)), и это поле также должно участвовать в связи наборов данных.

Резюме

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

← На главную