При разработке сложных отчетов на платформе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда визуально корректный запрос отказывается выполняться. Типичный сценарий: вы используете группировку по строковому коду счета (например, Хозрасчетный.Код), и запрос работает прекрасно, пока вы не добавляете инструкцию УПОРЯДОЧИТЬ ПО. В этот момент система выдает ошибку: «Поле не входит в группу "Хозрасчетный.Код"», несмотря на то, что это поле явно указано в секции СГРУППИРОВАТЬ ПО.
Рассмотрим детально, почему так происходит, разберем внутренние механизмы платформы и выясним, как правильно составить запрос, чтобы избежать подобных конфликтов.
Проанализируем ситуацию на примере кода, который часто вызывает затруднения. Предположим, мы хотим получить остатки по счетам и сгруппировать их только по коду, чтобы не перегружать выборку ссылочными типами:
ВЫБРАТЬ
СУММА(ХозрасчетныйОстатки.СуммаОстатокДт) КАК ОстатокДт,
ХозрасчетныйОстатки.Счет.Код КАК КодСчета
ИЗ
РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, , , ) КАК ХозрасчетныйОстатки
СГРУППИРОВАТЬ ПО
ХозрасчетныйОстатки.Счет.Код
УПОРЯДОЧИТЬ ПО
КодСчета
На первый взгляд, все логично: поле КодСчета присутствует в выборке и в группировке. Однако при выполнении этого кода (или при открытии его в конструкторе запроса) 1С выдает ошибку. Проблема кроется в том, как транслятор запросов 1С преобразует этот код в инструкции для SQL-сервера.
Выясним, как устроены планы счетов в 1С. В метаданных любого плана счетов существует свойство «Способ упорядочивания». Чаще всего это упорядочивание по коду. Но для СУБД (MS SQL, PostgreSQL и др.) обычная строка кода не всегда позволяет выстроить счета в правильном иерархическом порядке (например, чтобы счет «20.01» шел после «20»).
Для решения этой задачи платформа 1С создает в таблице БД скрытое поле OrderField (Порядок). Когда мы пишем в запросе УПОРЯДОЧИТЬ ПО Код, оптимизатор запросов 1С «под капотом» пытается заменить или дополнить это поле системным полем порядка. Но так как поле OrderField не включено в секцию СГРУППИРОВАТЬ ПО, SQL-сервер возвращает ошибку синтаксиса. Платформа видит, что для корректной сортировки ей нужны данные, которых нет в результате группировки.
Рассмотрим подробнее конструкцию ХозрасчетныйОстатки.Счет.Код. В терминах 1С это обращение «через точку». Платформа обрабатывает такие обращения следующим образом:
LEFT JOIN с основной таблицей плана счетов.УПОРЯДОЧИТЬ ПО, механизм генерации SQL пытается применить логику представления ссылочного типа (Счета). Для этого ему нужна Ссылка счета, чтобы получить доступ ко всем его атрибутам, включая скрытые поля индексации.Поскольку в блоке СГРУППИРОВАТЬ ПО указана только строка (Код), а не сама Ссылка, платформа теряет контекст объекта и не может гарантировать правильную сортировку по правилам плана счетов.
Самый простой и эффективный способ исправить ошибку — добавить Ссылка в блок группировки. Проанализируем исправленный вариант:
ВЫБРАТЬ
СУММА(ХозрасчетныйОстатки.СуммаОстатокДт) КАК ОстатокДт,
ХозрасчетныйОстатки.Счет.Код КАК КодСчета,
ХозрасчетныйОстатки.Счет КАК СчетСсылка
ИЗ
РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, , , ) КАК ХозрасчетныйОстатки
СГРУППИРОВАТЬ ПО
ХозрасчетныйОстатки.Счет,
ХозрасчетныйОстатки.Счет.Код
УПОРЯДОЧИТЬ ПО
КодСчета
Почему это работает? Когда в группировке участвует поле типа ПланСчетовСсылка, платформа получает «карт-бланш» на использование любых связанных с этой ссылкой полей в секции ORDER BY. Теперь генератор SQL-запросов может свободно добавлять поле OrderField, так как оно функционально зависит от Ссылки, и запрос становится корректным с точки зрения реляционной логики.
Если по каким-то причинам вы категорически не хотите видеть Ссылку в итоговом результате (хотя ее всегда можно просто не выводить в отчет), можно воспользоваться механизмом временных таблиц. Разберем этот подход по шагам:
// Шаг 1: Подготовка данных во временной таблице
ВЫБРАТЬ
ХозрасчетныйОстатки.Счет КАК Счет,
СУММА(ХозрасчетныйОстатки.СуммаОстатокДт) КАК Сумма
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
РегистрБухгалтерии.Хозрасчетный.Остатки КАК ХозрасчетныйОстатки
СГРУППИРОВАТЬ ПО
ХозрасчетныйОстатки.Счет;
// Шаг 2: Итоговая выборка с сортировкой
ВЫБРАТЬ
ВТ_Остатки.Счет.Код КАК КодСчета,
ВТ_Остатки.Сумма КАК Сумма
ИЗ
ВТ_Остатки КАК ВТ_Остатки
УПОРЯДОЧИТЬ ПО
ВТ_Остатки.Счет.Код
В данном случае на втором этапе группировка уже не используется, поэтому УПОРЯДОЧИТЬ ПО не вступает в конфликт с СГРУППИРОВАТЬ ПО. Платформа спокойно выполнит неявное соединение с планом счетов для получения кода и корректной сортировки.
Подводя итог, проанализируем основные правила работы с группировками в запросах 1С:
Остатки, Обороты) сами по себе выполняют группировку по измерениям. Если вы используете их без дополнительных соединений, вам может вообще не понадобиться секция СГРУППИРОВАТЬ ПО.ХозрасчетныйОстатки.Счет.Код в секции СГРУППИРОВАТЬ ПО заставляет систему делать лишнее соединение таблиц. Группировка по ХозрасчетныйОстатки.Счет с последующим получением кода в секции ВЫБРАТЬ — более оптимальный путь.Таким образом, странное поведение конструктора — это не ошибка платформы, а следствие работы защитных механизмов, которые гарантируют, что иерархические данные (каковыми являются счета) будут отсортированы правильно, согласно логике, заложенной в метаданных конфигурации.