При разработке сложных отчетов в Системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда один и тот же запрос выдает корректные данные в Консоли запросов, но возвращает неверные или "схлопнутые" результаты в самом отчете. Типичный пример — необходимость вывести остатки товаров на две разные даты в одном списке (например, на сегодня и на месяц назад). Разберем подробно, почему СКД "ломает" логику запроса и как заставить систему работать правильно.
Основная особенность СКД заключается в том, что она не просто выполняет ваш текст запроса, а выступает в роли генератора итогового запроса. Когда система анализирует набор данных, она видит использование виртуальных таблиц (например, Остатки). По умолчанию СКД стремится унифицировать работу с периодами. Если в запросе несколько раз вызывается виртуальная таблица одного и того же регистра, СКД может автоматически заменить ваши уникальные параметры (&КонДата, &МесяцНазад) на один стандартный параметр &Период.
Проанализируем ситуацию: в исходном запросе автора используются две временные таблицы, каждая из которых берет данные из регистра ТоварыНаСкладах.Остатки. Однако на выходе вместо двух разных цифр (29 и 35) система выдает одинаковые значения (29 и 29). Это происходит потому, что на этапе компоновки макета СКД подставила одну и ту же дату в обе виртуальные таблицы, проигнорировав логику объединения ОБЪЕДИНИТЬ.
Самый надежный и профессиональный способ запретить СКД вмешиваться в управление параметрами — это использование фигурных скобок {}. Рассмотрим, как должен выглядеть текст запроса, чтобы система не подменяла значения. Вместо стандартного обращения к виртуальной таблице, мы явно указываем параметры в расширении компоновки.
Посмотрим на пример правильного оформления параметров в тексте запроса:
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Склад,
ТоварыНаСкладахОстатки.Номенклатура,
ТоварыНаСкладахОстатки.КоличествоОстаток,
&КонДата КАК ГруппировкаПериод
ПОМЕСТИТЬ втТекущиеОстатки
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки({&КонДата}, ) КАК ТоварыНаСкладахОстатки;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Склад,
ТоварыНаСкладахОстатки.Номенклатура,
ТоварыНаСкладахОстатки.КоличествоОстаток,
&МесяцНазад КАК ГруппировкаПериод
ПОМЕСТИТЬ втОстаткиМесяцНазад
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки({&МесяцНазад}, ) КАК ТоварыНаСкладахОстатки;
Использование конструкции {&КонДата} сообщает системе компоновки: "Этот параметр управляется вручную, не пытайся заменить его на стандартный период". Это гарантирует, что в итоговом SQL-запросе к базе данных будут переданы именно те две разные даты, которые вы определили в настройках.
Если вы предпочитаете использовать конструктор запроса, разберем действия по шагам на уровне визуальных настроек:
&КонДата и &МесяцНазад в соответствующих полях, чтобы перекрыть стандартное поведение.Важный момент: если оставить флаг "Автозаполнение" в наборе данных включенным, СКД все равно может попытаться оптимизировать запрос. Для сложных отчетов с несколькими срезами часто рекомендуют отключать "Автозаполнение" и описывать доступные поля и параметры вручную.
Иногда проблема кроется не только в параметрах дат, но и в том, как СКД рассчитывает итоги по группировкам. В тексте запроса автора присутствует конструкция ИТОГИ ПО ГруппировкаПериод. В СКД использовать предложение ИТОГИ внутри текста запроса не рекомендуется.
Система компоновки данных сама строит дерево итогов на основе ваших настроек группировок. Наличие ИТОГИ в тексте может привести к конфликту структур. Вместо этого выполним следующие действия:
ИТОГИ ПО... и УПОРЯДОЧИТЬ ПО....ГруппировкаПериод установим роль Период. Это критично, если вы хотите, чтобы остатки не суммировались между датами, а отображались как последовательные срезы.ГруппировкаПериод.Если манипуляции с текстом запроса кажутся слишком громоздкими, проанализируем альтернативный вариант — использование нескольких Наборов данных - запрос.
Рассмотрим реализацию этого метода:
НаборДанных1, где получаем остатки только на &КонДата.НаборДанных2, где получаем остатки только на &МесяцНазад.Номенклатура и Склад.В этом случае параметры дат для каждой таблицы будут изолированы друг от друга, и СКД гарантированно не сможет их перепутать или объединить. Это "чистый" способ разделения логики, который упрощает отладку отчета.
Выясним, как точно узнать, что именно отправляет СКД в СУБД. Если результаты не сходятся, используйте программный метод вывода макета компоновки. В объекте КомпоновщикМакета после выполнения метода Выполнить() можно получить доступ к свойству МакетКомпоновки.Запросы.
Пример анализа программным кодом:
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновки);
Для Каждого ТекущийЗапрос Из МакетКомпоновки.Запросы Цикл
Сообщить(ТекущийЗапрос.Текст);
КонецЦикла;
Просмотрев этот текст, вы сразу увидите, подменила ли система ваши переменные &КонДата и &МесяцНазад на одну общую дату. Если вы видите в тексте дважды одно и то же значение параметра там, где должны быть разные — значит, необходимо вернуться к Решению 1 (фигурные скобки) или Решению 4 (разные наборы данных).
Подводя итог, помните: СКД — это мощный инструмент, который "думает" за разработчика. Чтобы получить предсказуемый результат в сложных отчетах с остатками, всегда явно ограничивайте область действия параметров виртуальных таблиц и доверяйте расчет итогов механизмам самой компоновки, а не тексту запроса.