Почему в СКД возникает ошибка «Поле не входит в группу», если в консоли запросов всё работает?

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

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

Выясним причину поведения СКД

Главное отличие выполнения запроса в обычной консоли от выполнения внутри СКД заключается в работе встроенного оптимизатора схемы компоновки. Если в наборе данных включено свойство Автозаполнение, СКД динамически модифицирует текст запроса перед его отправкой в СУБД:

  1. Компоновщик анализирует структуру настроек отчета (выбранные пользователем поля, группировки, отборы, сортировки).
  2. Поля, которые не используются в итоговом результате или вычислениях, автоматически вырезаются из секций ВЫБРАТЬ, в том числе во временных таблицах.
  3. Если во временной таблице присутствуют агрегатные функции, блоки СГРУППИРОВАТЬ ПО, сортировка УПОРЯДОЧИТЬ ПО или самосоединения с условиями в ГДЕ, удаление промежуточного поля приводит к нарушению синтаксической целостности конструкции. Поле может исчезнуть из выборки, но остаться в группировке или условии упорядочивания, что вызывает ошибку СУБД о невхождении поля в группу.

Способ 1. Установка признака «Обязательное» для полей временных таблиц

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

Разберем по шагам, как зафиксировать поля:

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

После установки этого признака компоновщик макета гарантированно оставит указанные поля в секции ВЫБРАТЬ исходного запроса, даже если конечный пользователь не вывел их в итоговый отчет.

Способ 2. Отключение автозаполнения и ручное управление полями

Если запрос содержит сложные многоуровневые временные таблицы, автоматическая модификация текста компоновщиком может приводить к трудноуловимым ошибкам. Рассмотрим вариант с отключением автоматического анализа:

  1. На вкладке Наборы данных снимем флаг Автозаполнение у набора данных-запроса.
  2. В этом случае СКД выполнит запрос в исходном виде, без вырезания полей.
  3. Если отчету требуются пользовательские отборы или динамические поля, опишем их явным образом с помощью фигурных скобок: синтаксиса {ВЫБРАТЬ ...}, {ГДЕ ...}.

Способ 3. Корректировка запроса: удаление лишней сортировки и замена алгоритма нумерации

Проанализируем фрагмент запроса, вызывающий сбой при самосоединении:


ВЫБРАТЬ
    ПЕРВЫЕ 10000
    КОЛИЧЕСТВО(*) КАК Номер,
    ВТ4.Соглашение,
    ВТ4.Путевой,
    ВТ4.КодировкаДоставки
ПОМЕСТИТЬ ВТ55
ИЗ
    ВТ4 КАК ВТ4,
    ВТ4 КАК ВТ41
ГДЕ
    ВТ4.КодировкаДоставки >= ВТ41.КодировкаДоставки
СГРУППИРОВАТЬ ПО
    ВТ4.Соглашение,
    ВТ4.Путевой,
    ВТ4.КодировкаДоставки    
УПОРЯДОЧИТЬ ПО
    ВТ4.КодировкаДоставки

В приведенном коде объединяются сразу несколько факторов риска:

  1. Конструкция УПОРЯДОЧИТЬ ПО во временной таблице. Использование сортировки при создании временной таблицы с группировкой избыточно и провоцирует СКД на некорректную сборку предложений группировки. Удалим строку УПОРЯДОЧИТЬ ПО ВТ4.КодировкаДоставки из запроса создания таблицы ВТ55.
  2. Квадратичная сложность самосоединения ($O(N^2)$). Соединение таблицы самой с собой по условию >= для вычисления порядкового номера резко замедляет работу отчета при росте числа записей, а при наличии дублей в поле КодировкаДоставки выдает неверные номера.

Посмотрим, какими штатными механизмами платформы 1С правильнее заменить самосоединение для получения нумерации:

  1. Функция АВТОНОМЕРЗАПИСИ(): начиная с платформы 8.3.13, во временных таблицах доступна штатная функция нумерации. Запрос становится компактным и быстрым:
    
    ВЫБРАТЬ
        АВТОНОМЕРЗАПИСИ() КАК Номер,
        ВТ4.Соглашение,
        ВТ4.Путевой,
        ВТ4.КодировкаДоставки
    ПОМЕСТИТЬ ВТ55
    ИЗ
        ВТ4 КАК ВТ4
    
  2. Системные поля СКД: если номер строки требуется только для визуального отображения, исключим его расчет из текста запроса и добавим в настройках отчета системное поле НомерПоПорядку или НомерПоПорядкуВГруппировке.
  3. Вычисляемые поля СКД: если номер нужен для расчета шага во времени, формулу смещения интервала можно вынести на вкладку Вычисляемые поля схемы компоновки, используя функцию НомерПоПорядку().

Способ 4. Программный перехват реального запроса СКД для точной отладки

Когда текст запроса объемный и визуально сложно понять, какое именно поле вызвало конфликт группировки, посмотрим на реальный исполняемый текст, который сформировал генератор макета.

Разберем программный код для получения фактического текста запроса:


КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(
    СхемаКомпоновкиДанных, 
    КомпоновщикНастроек.ПолучитьНастройки()
);

Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
    Если ТипЗнч(НаборДанных) = Тип("ЭлементМакетаКомпоновкиДанныхНаборДанныхЗапрос") Тогда
        РеальныйТекстЗапроса = НаборДанных.Запрос;
        // Полученный текст можно вывести в сообщение или скопировать в консоль запросов
    КонецЕсли;
КонецЦикла;

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

← На главную