Почему различаются результаты запроса в Консоли запросов и в СКД?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

Для успешного решения этой проблемы нам необходимо понять, что СКД — это не просто инструмент для вывода таблиц. Это мощный генератор отчетов, который полностью перестраивает исходный SQL-запрос «на лету» в зависимости от настроек пользователя, выбранных полей, группировок и отборов.

---

1. Влияние механизма автозаполнения и оптимизатора запросов СКД

Когда в наборе данных СКД включен флаг «Автозаполнение», система берет на себя управление полями, соединениями и группировками. Оптимизатор СКД анализирует текущие настройки отчета (какие поля выбраны пользователем на вкладке «Настройки», какие добавлены в группировки, а какие используются в отборах) и безжалостно удаляет все «лишние» элементы из итогового запроса.

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

Чтобы избежать этой проблемы и заставить СКД жестко выполнять важные для логики соединения, выполним следующие шаги:

  1. Перейдем на вкладку «Наборы данных» в схеме компоновки данных.
  2. Найдем поле, которое участвует в соединении или логике, но не выводится напрямую в отчет.
  3. Установим для этого поля флаг «Обязательное». Это заблокирует попытки оптимизатора СКД вырезать его из результирующего запроса.

---

2. Подмена параметров и периодов в виртуальных таблицах

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

Выясним причину: СКД сопоставляет параметры схемы компоновки данных с параметрами виртуальных таблиц. Если эти параметры не зафиксированы жестко, СКД может подставить вместо них границы периодов из пользовательских настроек, что приведет к неожиданному срезу данных.

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


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

Фигурные скобки { } указывают СКД, что данные параметры являются необязательными для расширения самой компоновкой, но если они заданы, то СКД должна использовать именно их, предотвращая автоматическую нежелательную подмену периодов.

---

3. Динамический перенос отборов в параметры виртуальных таблиц

Еще одна интеллектуальная оптимизация СКД — это динамический перенос пользовательских отборов. Если пользователь в режиме «1С:Предприятие» устанавливает простой отбор по организации в структуре отчета, СКД не просто добавляет условие ГДЕ в самый конец SQL-запроса.

Система пытается «пропихнуть» этот отбор как можно глубже — непосредственно в параметры виртуальных таблиц (например, в качестве первого субконто или измерения регистра). В консоли запросов мы чаще всего пишем статичные условия в секции ГДЕ. Из-за разного места применения фильтров СУБД строит принципиально разные планы запросов и может по-разному обрабатывать пустые значения (NULL) при соединениях, что опять же приводит к несовпадению итогов.

---

4. Специфика расчета ресурсов и остатков

При работе с остатками расхождения могут быть колоссальными. Это связано с тем, как СКД и Консоль запросов рассчитывают итоги.

Если в СКД настроены роли полей «Начальный остаток» и «Конечный остаток» (поля Роль на вкладке «Наборы данных»), система рассчитывает общие итоги по этим полям по бухгалтерским правилам:

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

5. Как увидеть реальный запрос, который выполняет СКД?

Чтобы прекратить гадание и точно понять, в чем причина расхождений, необходимо проанализировать реальный SQL-запрос, сформированный СКД после всех оптимизаций. Обычный текст запроса из схемы нам не поможет. Рассмотрим два эффективных способа получения исполняемого запроса.

Способ А. Использование специализированных консолей СКД

Рекомендуется использовать профессиональные инструменты разработчика, например, «Консоль компоновки данных» (входит в состав официального пакета «Инструменты разработчика» или поставляется отдельно). Эти консоли позволяют:

  1. Загрузить вашу схему компоновки данных (схема XML).
  2. Установить те же самые параметры и настройки пользователя, которые заданы в отчете.
  3. Нажать кнопку получения реального запроса. Программа покажет очищенный, готовый к выполнению SQL-запрос с учетом всех перенесенных отборов, удаленных неиспользуемых полей и внедренных параметров виртуальных таблиц.

Способ Б. Программный метод получения запроса через отладчик

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

  1. Откроем модуль объекта нашего отчета.
  2. Найдем (или создадим) предопределенную процедуру ПриКомпоновкеРезультата.
  3. Напишем код, который выполняет генерацию макета компоновки, и установим точку останова в самом конце.

Пример кода для перехвата макета компоновки:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Отключаем стандартный вывод, чтобы управлять процессом вручную
    СтандартнаяОбработка = Ложь;
    
    // Создаем установщик макета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    // Получаем макет компоновки
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
    
    // Точка останова должна стоять здесь!
    // В табло отладчика вычисляем: МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос
    
    // Далее идет стандартный вывод (для демонстрации)
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Запустим отчет в режиме отладки, дождемся остановки на указанной строке и добавим в табло отладчика выражение: МакетКомпоновки.НаборыДанных.[ИмяВашегоНабораДанных].Запрос. Полученный текст запроса будет содержать все изменения, внесенные СКД. Скопируйте его и вставьте в обычную Консоль запросов — теперь результаты совпадут до копейки!

← На главную