При разработке сложных отчетов в системе 1С программисты часто сталкиваются с необходимостью объединить данные из нескольких регистров накопления. Типичный пример — сопоставление остатков товаров на складах и материалов, переданных в производство (незавершенное производство — НЗП). Однако при попытке связать эти таблицы «в лоб» через левое соединение разработчики получают пустые строки вместо названий подразделений или сталкиваются с критическими ошибками компоновки данных.
В этой статье мы подробно разберем, почему возникает проблема исчезновения подразделений, проанализируем типичные ошибки при работе с ресурсами СКД и рассмотрим правильные архитектурные решения для построения таких отчетов.
Рассмотрим ситуацию: разработчик пытается собрать отчет по двум регистрам накопления — ТоварыНаСкладах и МатериалыВПроизводстве. Для этого он использует пакетный запрос с временными таблицами. Давайте взглянем на упрощенную схему исходного запроса, которая приводит к ошибке:
// Временная таблица 1: Материалы в производстве
ВЫБРАТЬ
ВтНЗП.Подразделение,
ВтНЗП.Затрата,
ВтНЗП.КоличествоКонечныйОстаток,
ВтНЗП.ПериодДень
ПОМЕСТИТЬ ВтНЗП
ИЗ
РегистрНакопления.МатериалыВПроизводстве.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , ) КАК ВтНЗП;
// Временная таблица 2: Товары на складах
ВЫБРАТЬ
ВтСклад.Номенклатура,
ВтСклад.КоличествоКонечныйОстаток,
ВтСклад.ПериодДень
ПОМЕСТИТЬ ВтСклад
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , ) КАК ВтСклад;
// Соединение таблиц
ВЫБРАТЬ
ВтСклад.Номенклатура,
ВтСклад.КоличествоКонечныйОстаток КАК ОстатокСклад,
ВтНЗП.КоличествоКонечныйОстаток КАК ОстатокНЗП,
ВтНЗП.Подразделение
ИЗ
ВтСклад КАК ВтСклад
ЛЕВОЕ СОЕДИНЕНИЕ ВтНЗП КАК ВтНЗП
ПО ВтСклад.Номенклатура = ВтНЗП.Затрата
И ВтСклад.ПериодДень = ВтНЗП.ПериодДень
При выполнении этого запроса в компоновке данных поле Подразделение для большинства строк оказывается пустым. Давайте разберемся, почему так происходит.
Главная архитектурная ошибка в данном запросе кроется в условии связи: И ВтСклад.ПериодДень = ВтНЗП.ПериодДень.
Виртуальные таблицы остатков и оборотов с периодичностью День возвращают записи только за те дни, в которых происходили реальные движения по конкретному регистру. Проанализируем простую жизненную ситуацию:
ВтСклад появляется строка с периодом 05.11.2023. В производстве по этому товару движений не было.ВтНЗП появляется строка с периодом 10.11.2023. На складе в этот день движений по селедке не было.Когда СУБД выполняет левое соединение по условию равенства дат, строка склада за 5-е число пытается сопоставиться со строками производства за 5-е число. Поскольку в производстве за 5-е число записей нет, СУБД возвращает для поля Подразделение значение NULL (которое в отчете выводится как пустая строка).
Аналогично, если мы попытаемся сделать соединение полным, строки за разные даты просто не пересекутся. Нам выведутся отдельные строки для склада за 5-е число (без подразделения) и отдельные строки для производства за 10-е число. Стыковки остатков по дням не произойдет.
Пытаясь обойти проблему пустых значений, разработчики часто пробуют назначить нечисловое поле Подразделение ресурсом на вкладке «Ресурсы» в схеме компоновки данных. Это приводит к двум популярным ошибкам.
Если поле добавлено в ресурсы, СКД накладывает жесткие ограничения на его использование. Возникает ошибка:
«Не допускается группировка по полю-ресурсу в колонках таблицы или точках диаграммы...»
Она означает, что в настройках структуры отчета (на вкладке «Настройки») поле Подразделение было ошибочно оставлено в роли группировки колонок или строк. Ресурсы в СКД предназначены исключительно для вычисления итоговых значений в точках пересечения группировок, их нельзя использовать в качестве самих осей группировки.
Для нечисловых полей (таких как справочники, перечисления или строки) нельзя использовать агрегатную функцию по умолчанию — СУММА. Попытка просуммировать ссылки на подразделения вызовет синтаксическую ошибку при выполнении запроса.
Если вам действительно необходимо сделать измерение (например, подразделение) ресурсом, чтобы оно агрегировалось на уровне вышестоящих группировок, в поле выражения на вкладке «Ресурсы» следует явно прописать функции выбора значений:
Максимум(Подразделение)Минимум(Подразделение)Это позволит СКД корректно выводить строковое или ссылочное значение на уровне итогов, если оно уникально в рамках группировки.
---
Рассмотрим два профессиональных подхода к проектированию таких отчетов в 1С, исключающих дублирование остатков и гарантирующих вывод всех необходимых аналитик.
Это самый надежный и производительный способ объединения разнородных данных в 1С. Вместо того чтобы пытаться связать таблицы по сложным условиям, мы объединяем их в один плоский поток данных, а СКД сама группирует строки по ключевым полям.
Разберем детально этот запрос:
ВЫБРАТЬ
Склад.Номенклатура КАК Номенклатура,
Склад.Склад КАК Склад,
ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка) КАК Подразделение,
Склад.КоличествоКонечныйОстаток КАК ОстатокСклад,
0 КАК ОстатокПроизводство
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК Склад
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Производство.Затрата,
ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка),
Производство.Подразделение,
0,
Производство.КоличествоКонечныйОстаток
ИЗ
РегистрНакопления.МатериалыВПроизводстве.Остатки(&Период, ) КАК Производство
Почему это работает правильно:
Номенклатура. Система автоматически схлопнет строки. В детальных записях мы увидим отдельно складские остатки (с заполненным складом) и производственные (с заполненным подразделением).Если объединение в одном запросе по каким-то причинам неудобно (например, требуется сложная логика работы с параметрами виртуальных таблиц), лучшим решением будет использование встроенного механизма связи наборов данных СКД. Это аналог левого соединения, выполняемый на уровне процессора компоновки данных без искажения итоговых сумм.
Выполним настройку по шагам:
Шаг 1. Создание наборов данных
В схеме компоновки данных создаем два независимых набора данных - запрос:
НаборДанныхСклад с текстом запроса:
ВЫБРАТЬ
Товары.Номенклатура КАК Номенклатура,
Товары.Склад КАК Склад,
Товары.КоличествоКонечныйОстаток КАК ОстатокСклад
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК Товары
НаборДанныхПроизводство с текстом запроса:
ВЫБРАТЬ
Материалы.Затрата КАК Номенклатура,
Материалы.Подразделение КАК Подразделение,
Материалы.КоличествоКонечныйОстаток КАК ОстатокПроизводство
ИЗ
РегистрНакопления.МатериалыВПроизводстве.Остатки(&Период, ) КАК Материалы
Шаг 2. Настройка связи наборов данных
Переходим на вкладку «Связи наборов данных» и добавляем новую строку:
НаборДанныхСкладНаборДанныхПроизводствоНоменклатура = Номенклатура&Период).При таком подходе СКД гарантирует корректный расчет итоговых показателей по складу и производству, исключая дублирование данных и пустые строки при выводе группировок.
Для создания корректных отчетов по нескольким регистрам накопления избегайте прямого соединения виртуальных таблиц по полям периодов (ПериодДень, ПериодСекунда) в запросе. Всегда отдавайте предпочтение структуре запроса с оператором ОБЪЕДИНИТЬ ВСЕ или связывайте независимые наборы данных средствами самой СКД.