Почему при изменении формулы одного ресурса в СКД меняются значения других полей и как это исправить?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

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

Анализируем ситуацию: механизм оптимизации запросов СКД

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

  1. Анализирует настройки отчета: смотрит, какие поля выбраны пользователем, какие группировки используются и какие ресурсы участвуют в расчете.
  2. Оптимизирует текст запроса: исключает из итогового SQL-запроса все поля и таблицы, которые не задействованы в текущей компоновке.
  3. Перестраивает группировки: если какое-то поле удаляется, СКД пересматривает секцию СГРУППИРОВАТЬ ПО, чтобы запрос работал максимально быстро.

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

Шаг 1: Проверка итогового текста запроса

Чтобы убедиться в том, что СКД «режет» ваш запрос, необходимо посмотреть на реальный текст запроса, который отправляется в СУБД. Сделать это можно в модуле объекта отчета. Разберем программный код, который позволит вывести итоговый запрос в окно сообщений:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Получаем текущие настройки пользователя
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    // Создаем компоновщик макета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    // Генерируем макет компоновки
    МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    // Проверяем наличие наборов данных и выводим запрос первого набора
    Если МакетКомпоновкиДанных.НаборыДанных.Количество() > 0 Тогда
        Сообщить(МакетКомпоновкиДанных.НаборыДанных[0].Запрос);
    КонецЕсли;
    
КонецПроцедуры

Сравнив текст запроса в двух случаях (с работающей формулой и с «проблемной»), вы увидите, что в проблемном варианте из секций ВЫБРАТЬ и СГРУППИРОВАТЬ ПО исчезли ключевые поля. Рассмотрим на примере, как меняется структура при оптимизации:

Вариант 1 (полный запрос):


ВЫБРАТЬ
    Номенклатура,
    МАКСИМУМ(КоличествоКонечныйОстаток) КАК КонечныйОстаток,
    СУММА(КоличествоОборот) КАК КоличествоОборот
ИЗ
    вт_Остатки
СГРУППИРОВАТЬ ПО
    Номенклатура,
    Период

Вариант 2 (оптимизированный СКД):


ВЫБРАТЬ
    Номенклатура,
    МАКСИМУМ(КоличествоКонечныйОстаток) КАК КонечныйОстаток
ИЗ
    вт_Остатки
СГРУППИРОВАТЬ ПО
    Номенклатура

Обратите внимание: исчезновение поля КоличествоОборот позволило системе убрать Период из группировки. В результате МАКСИМУМ теперь считается не по каждому периоду отдельно, а по всей номенклатуре в целом, что и приводит к «чудесному» изменению цифр в отчете.

Шаг 2: Использование свойства «Обязательное»

Чтобы запретить СКД исключать поле из запроса, даже если оно явно не используется в выбранных полях или ресурсах, необходимо воспользоваться свойством Обязательное (Mandatory). Выясним, как это настроить:

  1. Откроем Схему компоновки данных.
  2. Перейдем на закладку Наборы данных.
  3. Найдем в списке полей то поле, которое пропадает (в нашем примере это КоличествоОборот).
  4. В колонке Обязательное установим флажок.

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

Шаг 3: Особенности расчета остатков и ролей полей

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

Если при оптимизации запроса СКД удаляет поле периода, она может потерять контекст расчета остатков. В настройках роли поля (вкладка «Наборы данных» -> колонка «Роль») убедитесь, что:

Дополнительные рекомендации

При проектировании сложных отчетов на СКД полезно придерживаться следующих правил:

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

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

← На главную