При разработке сложных отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с необходимостью объединить данные из разных источников (например, производство и отгрузку) в одну иерархическую структуру. Типичная проблема заключается в том, что при простом соединении таблиц данные начинают «дублироваться» или выводиться некорректно в общих колонках ресурсов. Рассмотрим, как правильно организовать вывод таких данных и реализовать сопоставление по методу ФИФО.
Проанализируем ситуацию: у нас есть документы СборкаЗапасов (производство) и РасходнаяНакладная (отгрузка). Мы хотим видеть их в одной колонке «Количество», но чтобы значение бралось из соответствующего документа. Казалось бы, достаточно использовать конструкцию ВЫБОР КОГДА в вычисляемом поле или запросе. Однако при использовании соединений (JOIN) в рамках одного набора данных строка результата часто содержит ссылки на оба документа одновременно (если они связаны по заказу). В этом случае система всегда находит первое истинное условие и выводит только одно значение (например, всегда количество производства), игнорируя контекст строки.
Выясним причину: СКД при выполнении запроса формирует плоскую таблицу. Если по одному заказу есть и производство, и отгрузка, соединение «размножает» строки. Чтобы решить задачу элегантно, воспользуемся механизмом ресурсов СКД или разделением наборов данных.
Это самый эффективный метод, к которому пришел автор темы. Его суть заключается в том, чтобы не пытаться вычислить поле «на лету» в запросе, а позволить СКД рассчитать его в момент формирования конкретной группировки отчета. Разберем по шагам:
КоличествоОбщее), оставив выражение пустым.КоличествоОбщее в список ресурсов дважды.Сумма(КоличествоПроизводство). В колонке «Рассчитывать по...» выберем группировку ДокументПроизводства.Сумма(КоличествоОтгрузка). В колонке «Рассчитывать по...» выберем группировку ДокументОтгрузки.Таким образом, когда СКД будет выводить строку с производством, она применит первое правило, а когда с отгрузкой — второе. В итоговой колонке мы получим корректные цифры без смешивания данных.
Если мы хотим решить задачу на уровне запроса, проанализируем ситуацию с объединением таблиц. Вместо соединения (JOIN) лучше использовать объединение (UNION ALL). Рассмотрим пример структуры запроса:
ВЫБРАТЬ
Сборка.ЗаказПокупателя КАК ЗаказПокупателя,
Сборка.Номенклатура КАК Номенклатура,
Сборка.Ссылка КАК ДокументДвижения,
Сборка.Количество КАК КоличествоПроизводство,
0 КАК КоличествоОтгрузка
ИЗ
Документ.СборкаЗапасов КАК Сборка
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Расходная.ЗаказПокупателя,
Расходная.Номенклатура,
Расходная.Ссылка,
0,
Расходная.Количество
ИЗ
Документ.РасходнаяНакладная КАК Расходная
При такой структуре в каждой строке будет заполнено только одно из полей (либо производство, либо отгрузка). Теперь в вычисляемом поле мы можем спокойно написать:
ЕСТЬNULL(КоличествоПроизводство, 0) + ЕСТЬNULL(КоличествоОтгрузка, 0)
Это значение будет всегда корректным для текущей строки документа.
Вторая часть задачи — сопоставление произведенной продукции и отгруженной по методу ФИФО (первым произведено — первым отгружено). Реализовать это чистым запросом без оконных функций крайне сложно, поэтому рассмотрим алгоритм с использованием временных таблиц и нарастающих итогов.
Рассмотрим подробнее логику расчета:
Проанализируем пример кода для получения нарастающего итога (для платформы 8.3.20+):
ВЫБРАТЬ
Т.Заказ,
Т.Номенклатура,
Т.Ссылка,
Т.Количество,
СУММА(Т.Количество) НАД(ПАРТИЦИЯ ПО Т.Заказ, Т.Номенклатура УПОРЯДОЧИТЬ ПО Т.Ссылка.МоментВремени) КАК Накоплено
ИЗ
ВТ_Данные КАК Т
Если ваша платформа ниже 8.3.20, нарастающий итог придется получать соединением таблицы самой с собой по условию Т1.МоментВремени >= Т2.МоментВремени, что может замедлить отчет при больших объемах данных.
При работе с СКД важно помнить о функции ЕСТЬNULL. Посмотрим на ситуацию: если при соединении таблиц данных по отгрузке нет, система вернет NULL. Любая математическая операция с NULL (например, КоличествоПроизводство - NULL) вернет NULL, и результат в отчете будет пустым.
Всегда используйте проверку в выражениях ресурсов:
Сумма(ЕСТЬNULL(КоличествоПроизводство, 0)) - Сумма(ЕСТЬNULL(КоличествоОтгрузка, 0))
Также обратите внимание на условия в запросе. Проверка Документ.Проведен И Документ.ПометкаУдаления = ЛОЖЬ является избыточной. В системе 1С проведенный документ по определению не может быть помечен на удаление. Достаточно использовать только Ссылка.Проведен для оптимизации производительности запроса.
Подводя итог, отметим: решение через связи наборов данных в СКД зачастую предпочтительнее сложных JOIN в одном запросе, так как оно позволяет системе компоновки автоматически управлять контекстом записей и избегать дублирования итогов, что и требовалось в исходной задаче.