Как исправить ошибку «Нельзя использовать производные от полей составного типа в выражениях» в запросах 1С

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

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

В этой статье мы подробно разберем, почему возникает эта ситуация, проанализируем техническую подоплеку работы платформы 1С с составными типами данных и рассмотрим три эффективных способа решения задачи.

Причина возникновения ошибки

Разберем ситуацию на примере из практики. Автор темы изменил измерение ДокументПланирования в регистре накопления ПланируемыеПоступленияДенежныхСредств, сделав его составным (добавив, например, тип Документ.ЗаказПокупателя). В тексте запроса происходит обращение к реквизиту этого поля через точку: ПланируемыеДвиженияОстатки.ДокументПланирования.ВалютаДокумента.

Когда поле имеет составной тип, платформа 1С на уровне СУБД выполняет неявное левое соединение (LEFT JOIN) со всеми таблицами тех объектов, которые входят в этот тип. Если мы пытаемся сгруппировать результат по самому составному полю (ссылке), но в секции ВЫБРАТЬ используем его реквизиты внутри конструкций ВЫБОР или ВЫРАЗИТЬ, возникает конфликт. Система не может однозначно сопоставить «разыменованное» поле в выборке с полем группировки, так как для СУБД это разные колонки из разных таблиц.

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

Способ №1. Явное приведение типов через ВЫРАЗИТЬ

Самый правильный и производительный способ решения проблемы — это подсказать платформе, к какому именно типу данных мы обращаемся. Это избавляет систему от необходимости строить соединения со всеми возможными таблицами составного типа.

Проанализируем, как это применить в коде. Вместо прямого обращения к реквизиту составного поля, мы используем конструкцию ВЫРАЗИТЬ:


ВЫБРАТЬ
    СУММА(ПланируемыеОстатки.СуммаОстаток) КАК Сумма,
    ВЫРАЗИТЬ(ПланируемыеОстатки.ДокументПланирования КАК Документ.ЗаказПокупателя).ВалютаДокумента КАК Валюта
ИЗ
    РегистрНакопления.ПланируемыеПоступленияДенежныхСредств.Остатки КАК ПланируемыеОстатки
СГРУППИРОВАТЬ ПО
    ВЫРАЗИТЬ(ПланируемыеОстатки.ДокументПланирования КАК Документ.ЗаказПокупателя).ВалютаДокумента

Важный момент: если вы используете выражение с ВЫРАЗИТЬ в секции ВЫБРАТЬ, оно должно быть точно таким же в секции СГРУППИРОВАТЬ ПО. Это позволяет оптимизатору запросов корректно сопоставить поля.

Способ №2. Использование временных таблиц

Если логика запроса слишком сложна (как в исходном сообщении темы, где присутствуют множественные проверки условий в блоке ВЫБОР), использование ВЫРАЗИТЬ в каждой строке может сделать код нечитаемым. В этом случае мы рекомендуем использовать механизм временных таблиц. Это «золотой стандарт» профессиональной разработки на 1С.

Рассмотрим алгоритм действий:

  1. Создаем первый запрос, который просто выбирает данные из регистра и «вытаскивает» нужные реквизиты составных полей в отдельные колонки.
  2. Помещаем этот результат во временную таблицу.
  3. Во втором запросе обращаемся к этой временной таблице и выполняем группировку (СУММА, МИНИМУМ и т.д.) уже по плоским полям.

Пример реализации такой структуры:


// Шаг 1: Подготовка данных
ВЫБРАТЬ
    ПланируемыеОстатки.ДокументПланирования КАК ДокументСсылка,
    ВЫРАЗИТЬ(ПланируемыеОстатки.ДокументПланирования КАК Документ.ЗаказПокупателя).ВалютаДокумента КАК ВалютаДокумента,
    ПланируемыеОстатки.СуммаОстаток КАК Сумма
ПОМЕСТИТЬ ВТ_ИсходныеДанные
ИЗ
    РегистрНакопления.ПланируемыеПоступленияДенежныхСредств.Остатки КАК ПланируемыеОстатки;

// Шаг 2: Группировка и расчеты
ВЫБРАТЬ
    ВТ.ДокументСсылка,
    ВТ.ВалютаДокумента,
    СУММА(ВТ.Сумма) КАК ИтоговаяСумма
ИЗ
    ВТ_ИсходныеДанные КАК ВТ
СГРУППИРОВАТЬ ПО
    ВТ.ДокументСсылка,
    ВТ.ВалютаДокумента

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

Способ №3. Использование вложенных запросов

Как отметил один из участников обсуждения (сообщение №9), в некоторых случаях (например, в динамических списках, где нельзя использовать временные таблицы) помогает «упаковка» исходного запроса во вложенный.

Выясним, как это работает. Мы выносим обращение к реквизитам «через точку» на нижний уровень вложенности, а группировку делаем на верхнем уровне. Платформа сначала получает выборку со всеми значениями, а затем агрегирует её.

Рассмотрим структуру такого запроса:


ВЫБРАТЬ
    Вложенный.ДокументПланирования,
    Вложенный.ВалютаДокумента,
    СУММА(Вложенный.СуммаПлатежа) КАК СуммаПлатежа
ИЗ (
    ВЫБРАТЬ
        ПланируемыеДвижения.ДокументПланирования КАК ДокументПланирования,
        ПланируемыеДвижения.ДокументПланирования.ВалютаДокумента КАК ВалютаДокумента,
        ПланируемыеДвижения.СуммаПлатежа КАК СуммаПлатежа
    ИЗ
        РегистрНакопления.ПланируемыеПоступленияДенежныхСредств КАК ПланируемыеДвижения
) КАК Вложенный
СГРУППИРОВАТЬ ПО
    Вложенный.ДокументПланирования,
    Вложенный.ВалютаДокумента

Хотя этот метод рабочий, мы рекомендуем отдавать предпочтение временным таблицам (Способ №2) в обычных отчетах и обработках, так как это упрощает отладку и зачастую работает быстрее на больших объемах данных.

Оптимизация производительности при работе с составными полями

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

Проанализируем несколько советов по оптимизации:

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

← На главную