При работе с Системой компоновки данных (СКД) в платформах 1С 8.3 разработчики часто сталкиваются с ситуацией, когда верный запрос в консоли начинает выводить некорректные итоговые данные в отчете. Проанализируем причину такого поведения и разберем способы его устранения.
Система компоновки данных оснащена механизмом динамической оптимизации запросов. Если поле из промежуточной временной таблицы не выбирается напрямую для вывода в отчет и не используется в пользовательских группировках или отборах, СКД считает его лишним. На этапе компоновки макета платформа автоматически вырезает это поле из секций ВЫБРАТЬ и СГРУППИРОВАТЬ ПО пакетного запроса.
Если удаленное поле участвовало в промежуточной детализации данных совместно с агрегатными функциями (например, СУММА или МАКСИМУМ), уровень группировки во временной таблице меняется. В результате итоговые расчеты сворачиваются по другой структуре полей и дают искаженные значения.
Рассмотрим первый эффективный подход. Механизм оптимизации СКД удаляет неиспользуемые поля из секций временных таблиц, но не оптимизирует состав полей внутри вложенных запросов (ИЗ (ВЫБРАТЬ ...)). Если перенести промежуточные вычисления из временных таблиц во вложенные запросы, платформа сохранит исходный состав полей и корректность группировок.
Разберем данный подход на примере пакета запросов, где промежуточный расчет выполняется во временной таблице:
ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
НаборыВступительныхИспытанийПредметы.Ссылка КАК Ссылка,
НаборыВступительныхИспытанийПредметы.Предмет КАК Предмет,
НаборыВступительныхИспытанийПредметы.ФормаИспытания КАК ФормаИспытания,
ЗаявленияПоступающихСрезПоследних.ФизическоеЛицо КАК ФизическоеЛицо,
ЗаявленияПоступающихСрезПоследних.Регистратор КАК Регистратор
ПОМЕСТИТЬ Наборы
ИЗ
РегистрСведений.ЗаявленияПоступающих.СрезПоследних КАК ЗаявленияПоступающихСрезПоследних
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НаборыВступительныхИспытаний.Предметы КАК НаборыВступительныхИспытанийПредметы
ПО ЗаявленияПоступающихСрезПоследних.НаборВступительныхИспытаний = НаборыВступительныхИспытанийПредметы.Ссылка
ГДЕ
НаборыВступительныхИспытанийПредметы.ФормаИспытания = &ФормаИспытанияЕГЭ
И ЗаявленияПоступающихСрезПоследних.ПриемнаяКампания = &ПриемнаяКампания
;
Если обернуть логику выбора данных во вложенный запрос непосредственно в секции ИЗ основного запроса, СКД не сможет вырезать промежуточные поля группировки, так как структура подзапроса останется фиксированной.
Рассмотрим второй вариант — управление полями набора данных с помощью отключения автозаполнения и использования языка компоновки данных непосредственно в тексте запроса. В этом случае мы явно задаем доступные поля компоновки в фигурных скобках {}.
Проанализируем пошагово, как правильно оформить запрос с отключенным автозаполнением:
{ВЫБРАТЬ} и {ГДЕ} для указания полей, которые будут доступны для выбора и фильтрации.{ВЫБРАТЬ}.Посмотрим на пример структуры запроса с использованием расширения языка компоновки данных:
ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
НаборыВступительныхИспытанийПредметы.Ссылка КАК Ссылка,
НаборыВступительныхИспытанийПредметы.Предмет КАК Предмет,
НаборыВступительныхИспытанийПредметы.ФормаИспытания КАК ФормаИспытания,
ЗаявленияПоступающихСрезПоследних.ФизическоеЛицо КАК ФизическоеЛицо,
НаборыВступительныхИспытанийПредметы.НомерСтроки КАК НомерСтроки,
ЗаявленияПоступающихСрезПоследних.Регистратор КАК Регистратор
{ВЫБРАТЬ
ФизическоеЛицо.* КАК ФизическоеЛицо,
Ссылка.* КАК Ссылка,
Регистратор.* КАК Регистратор}
ПОМЕСТИТЬ Наборы
ИЗ
РегистрСведений.ЗаявленияПоступающих.СрезПоследних({&Период}) КАК ЗаявленияПоступающихСрезПоследних
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НаборыВступительныхИспытаний.Предметы КАК НаборыВступительныхИспытанийПредметы
ПО ЗаявленияПоступающихСрезПоследних.НаборВступительныхИспытаний = НаборыВступительныхИспытанийПредметы.Ссылка
{ГДЕ
НаборыВступительныхИспытанийПредметы.ФормаИспытания = &ФормаИспытанияЕГЭ
И ЗаявленияПоступающихСрезПоследних.ПриемнаяКампания = &ПриемнаяКампания}
;
ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
РезультатыВступительныхИспытанийСрезПоследних.Предмет КАК Предмет,
РезультатыВступительныхИспытанийСрезПоследних.ФормаИспытания КАК ФормаИспытания,
Наборы.Ссылка КАК Ссылка,
Наборы.ФизическоеЛицо КАК ФизическоеЛицо,
РезультатыВступительныхИспытанийСрезПоследних.ОценкаПриоритетОценки КАК ОценкаПриоритетОценки,
Наборы.Регистратор КАК Регистратор
{ВЫБРАТЬ
ФизическоеЛицо.* КАК ФизическоеЛицо,
Ссылка.* КАК Ссылка,
Регистратор.* КАК Регистратор}
ПОМЕСТИТЬ резНабор
ИЗ
Наборы КАК Наборы
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_РезультатыВступительныхИспытанийСрезПоследних КАК РезультатыВступительныхИспытанийСрезПоследних
ПО Наборы.Предмет = РезультатыВступительныхИспытанийСрезПоследних.Предмет
И Наборы.ФормаИспытания = РезультатыВступительныхИспытанийСрезПоследних.ФормаИспытания
И Наборы.ФизическоеЛицо = РезультатыВступительныхИспытанийСрезПоследних.ФизическоеЛицо
;
ВЫБРАТЬ
резНабор.ФизическоеЛицо КАК ФизическоеЛицо,
резНабор.Ссылка КАК Ссылка,
СУММА(резНабор.ОценкаПриоритетОценки) КАК ОценкаПриоритетОценки,
резНабор.Регистратор КАК Регистратор
{ВЫБРАТЬ
ФизическоеЛицо.* КАК ФизическоеЛицо,
Ссылка.* КАК Ссылка,
ОценкаПриоритетОценки КАК ОценкаПриоритетОценки,
Регистратор.* КАК Регистратор}
ИЗ
резНабор КАК резНабор
{ГДЕ
резНабор.ФизическоеЛицо = &ФизическоеЛицо}
СГРУППИРОВАТЬ ПО
резНабор.ФизическоеЛицо,
резНабор.Ссылка,
резНабор.Регистратор
Существует еще несколько альтернативных решений, когда необходимо сохранить пакет временных таблиц без переработки вложенных запросов:
ГДЕ: Добавим во временную таблицу условие вида ГДЕ ИмяПоля = ИмяПоля или ГДЕ НЕ ИмяПоля ЕСТЬ NULL ИЛИ ИмяПоля ЕСТЬ NULL. Платформа сочтет поле используемым в отборе и не станет исключать его из текста запроса.ПриКомпоновкеРезультата) с использованием объекта МенеджерВременныхТаблиц. Переданный в СКД менеджер содержит уже готовые таблицы, структуру которых оптимизатор изменить не может.Подводя итог: для гарантированного сохранения группировок наиболее удобны два метода — перевод расчетной части во вложенные запросы или отключение автозаполнения с ручным описанием полей компоновки.