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