Почему пропадают данные при объединении наборов данных в СКД и как это правильно настроить?

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

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

Разберем механизм работы «Набора данных - объединение»

Прежде всего, проанализируем, как именно СКД обрабатывает объединение наборов. Вопреки распространенному мнению, это не просто аналог UNION ALL из языка SQL. На самом деле СКД выполняет операцию, более похожую на FULL OUTER JOIN по полям, которые имеют одинаковые псевдонимы во всех объединяемых наборах.

Если мы объединяем два набора по полям Номенклатура и Период, система ожидает, что значения в этих полях будут идентичны до последнего байта и секунды. Если в одном наборе поле заполнено, а в другом — нет, или если в настройках не указано, что числовые показатели являются ресурсами, СКД выведет их как разные записи. Выясним основные причины «исчезновения» или дублирования строк.

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

Одной из самых частых причин того, что поле «Количество потребность» не заполняется при наличии данных в колонке «Приход», является отсутствие этих полей на вкладке «Ресурсы». Если поля не определены как ресурсы, СКД не знает, что их нужно суммировать при группировке. В итоге система просто выводит первое попавшееся значение для данной комбинации группировок (Номенклатура + Дата), которое вполне может оказаться NULL или пустым.

Что нужно сделать:

  1. Перейдем на закладку «Ресурсы» в схеме компоновки данных.
  2. Добавим поля КоличествоПотребность и КоличествоПриход в список ресурсов.
  3. Убедимся, что в колонке «Выражение» установлена агрегатная функция СУММА().

Только после этого СКД «схлопнет» строки по одинаковой номенклатуре и дате, сложив значения из разных источников в одну и ту же строку отчета.

Проблема 2: Точность дат и приведение к началу дня

Проанализируем ситуацию с датами. В 1С тип Дата содержит время с точностью до секунды. Если в вашей Таблице Значений (ТЗ) дата записана как 01.10.2023 00:00:00, а в запросе к регистру (из-за его периодичности или времени проведения документа) дата выглядит как 01.10.2023 14:30:15, то для СКД это разные значения. Объединения не произойдет, и данные разойдутся по разным строкам.

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


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

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


НоваяСтрока = ТаблицаПотребностей.Добавить();
НоваяСтрока.Номенклатура = ТекущийТовар;
НоваяСтрока.ДатаПотребности = НачалоДня(ВыбраннаяДата);
НоваяСтрока.Количество = ТекущееКоличество;

Проблема 3: Роли полей и работа с остатками

Если вы объединяете данные, содержащие остатки (например, остаток на начало месяца из регистра и потребность из ТЗ), критически важно настроить Роли полей на закладке «Наборы данных». Без этого итоги по остаткам будут рассчитываться некорректно (удваиваться при сложении или обнуляться).

Проанализируем необходимые настройки ролей:

  1. Поле периода: Для полей даты в обоих наборах установите роль «Период». Если это основной период, укажите порядковый номер (например, 1). Это подскажет СКД, как сопоставлять временные оси разных наборов.
  2. Поля остатков: Если в запросе используются начальные и конечные остатки, им нужно назначить роли НачальныйОстаток и КонечныйОстаток соответственно. При этом важно указать «Имя» для связи — оно должно быть одинаковым для обоих полей (например, Количество), чтобы система понимала, что это показатели одного и того же ресурса.
  3. Игнорирование NULL: СКД иногда специфически обрабатывает пустые значения. Убедитесь, что типы данных в колонках ТЗ и в запросе совпадают (например, оба имеют тип Число(15, 3)).

Типизация внешней Таблицы Значений

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

Рассмотрим, как правильно создать типизированную таблицу:


КЧ = Новый КвалификаторыЧисла(15, 3);
ОписаниеТипаЧисло = Новый ОписаниеТипов("Число", КЧ);
ОписаниеТипаДата = Новый ОписаниеТипов("Дата");

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("ДатаПотребности", ОписаниеТипаДата);
ТЗ.Колонки.Добавить("КоличествоПотребность", ОписаниеТипаЧисло);

Важный момент: Имена колонок в ТЗ и псевдонимы полей в запросе должны совпадать с учетом регистра. Для СКД номенклатура и Номенклатура — это разные поля, и автоматического объединения по ним не произойдет.

Альтернативный подход: Связи наборов данных

В некоторых случаях использование «Набора данных - объединение» может быть избыточным или неудобным. Если вам нужно к «плановым» данным из ТЗ просто «подтянуть» фактические данные из регистра, рассмотрим использование Связей наборов данных (аналог Left Join).

Пошаговый алгоритм:

  1. Создайте два отдельных набора данных (например, НаборТЗ и НаборЗапрос).
  2. Перейдите на закладку «Связи наборов данных».
  3. Укажите НаборТЗ как источник связи, а НаборЗапрос как приемник.
  4. В качестве условий связи выберите Номенклатура и ДатаПотребности = ПериодДень.

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

Как проверить, что происходит «под капотом»?

Для глубокого анализа ситуации рекомендуется использовать внешнюю обработку «Консоль компоновки данных». Она позволяет сформировать отчет и увидеть исполняемый запрос, который СКД генерирует во временных таблицах базы данных. Проанализировав этот запрос, вы сразу увидите, почему записи не соединяются: либо из-за разницы в секундах дат, либо из-за несовпадения типов, либо из-за формирования лишних NULL значений в местах объединения.

Подведем итог: для корректного объединения наборов в СКД всегда проверяйте идентичность типов данных, используйте начало периода для дат, назначайте полям роли и не забывайте добавлять числовые показатели в ресурсы с функцией СУММА().

← На главную