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