При разработке отчетов на платформе 1С:Предприятие 8 начинающие программисты часто сталкиваются с ситуацией, когда код синтаксически кажется верным, но система выдает ошибку при выполнении запроса. Разберем типичную ситуацию: необходимо просуммировать количество заявок по водителям, используя данные документов РасходнаяНакладная, но выполнение метода Выполнить() прерывается с системным сообщением об ошибке. Проанализируем причины этой проблемы и найдем способы её решения.
Рассмотрим основной нюанс обращения к метаданным. В языке запросов 1С существует строгое правило именования таблиц, которое отличается от синтаксиса встроенного языка. Выясним причину возникновения ошибки в исходном коде автора:
Во встроенном языке для работы с коллекциями объектов мы используем множественное число, например: Документы.РасходнаяНакладная.Выбрать(). Однако в языке запросов имена таблиц всегда указываются в единственном числе.
Вместо ошибочного:
|Из
|Документы.РасходнаяНакладная
Необходимо использовать правильное обращение:
|Из
|Документ.РасходнаяНакладная КАК РасходнаяНакладная
Это самая распространенная причина, по которой конструктор запроса или сам обработчик не может найти таблицу в базе данных. Помните: Документ.Имя, Справочник.Имя, РегистрСведений.Имя — это стандарт де-факто для языка SQL в 1С.
Проанализируем следующую ошибку в коде — использование секции СГРУППИРОВАТЬ ПО. В запросе автора указано: СГРУППИРОВАТЬ ПО Итого. Это синтаксически неверно по двум причинам:
СГРУППИРОВАТЬ ПО должны входить все поля, перечисленные в ВЫБРАТЬ, к которым не применены агрегатные функции (такие как СУММА, КОЛИЧЕСТВО, МАКСИМУМ). В нашем случае это поле Водитель.ИТОГИ используется в языке запросов 1С для построения иерархических результатов (дерева), а не для простой группировки строк. Его нельзя использовать внутри СГРУППИРОВАТЬ ПО.Рассмотрим, как должен выглядеть корректный текст запроса с группировкой по водителю и расчетом суммы заявок:
Запрос.Текст =
"ВЫБРАТЬ
| РасходнаяНакладная.Водитель КАК Водитель,
| СУММА(РасходнаяНакладная.КолвоЗаявок) КАК КолвоЗаявок
|ИЗ
| Документ.РасходнаяНакладная КАК РасходнаяНакладная
|
|СГРУППИРОВАТЬ ПО
| РасходнаяНакладная.Водитель";
Обратите внимание на использование КАК КолвоЗаявок. Это создание псевдонима (алиаса). Без него поле в результате запроса будет называться автоматически (например, КолвоЗаявокСумма), и метод Параметры.Заполнить(Выборка) в макете не сможет найти соответствие между полем запроса и параметром области макета.
Посмотрим на структуру процедуры ЗаполнитьТабДок. Автор сначала делает перебор всех документов через Документы.РасходнаяНакладная.Выбрать(), а затем выполняет отдельный запрос для получения итогов. Это крайне неэффективный подход, особенно на больших объемах данных.
Разберем, почему лучше использовать один запрос:
Выбрать() тянет из базы данных все поля документа, включая табличные части, что создает огромную нагрузку на сеть и сервер.ВЫБРАТЬ.ОбходРезультатаЗапроса.ПоГруппировкам.Рекомендуется переписать код так, чтобы сначала выполнялся запрос, получающий и детальные строки, и итоги, а затем результат выводился в ТабличныйДокумент.
Рассмотрим вопрос о том, как обращаться к текстовым столбцам (типа «Строка»). Если поле имеет фиксированную или ограниченную длину (например, Строка(100)), вы можете работать с ним как с обычным измерением: группировать по нему, сортировать или использовать в условиях.
Однако, если поле имеет неограниченную длину (тип «Текст» в базе данных), при попытке группировки система выдаст ошибку. В этом случае проанализируем ситуацию и применим функцию ВЫРАЗИТЬ:
|ВЫБРАТЬ
| ВЫРАЗИТЬ(РасходнаяНакладная.Комментарий КАК СТРОКА(150)) КАК КомментарийКратко
|...
|СГРУППИРОВАТЬ ПО
| ВЫРАЗИТЬ(РасходнаяНакладная.Комментарий КАК СТРОКА(150))
Эта функция обрезает длинный текст до указанного количества символов, превращая его в строку ограниченной длины, которую 1С уже может эффективно сравнивать и группировать.
С учетом всех исправлений, процедура формирования отчета должна выглядеть следующим образом:
&НаСервереБезКонтекста
Процедура ЗаполнитьТабДок(ТабДок)
ТабДок.Очистить();
Макет = Отчеты.ОтчетПоЗаказам.ПолучитьМакет("Отчёт");
ОблШапка = Макет.ПолучитьОбласть("Шапка");
ОблЭлемент = Макет.ПолучитьОбласть("Элемент");
ОблИтого = Макет.ПолучитьОбласть("Итого");
ОблШапка.Параметры.ДатаОтчёта = Формат(ТекущаяДата(),"ДЛФ=DD" );
ТабДок.Вывести(ОблШапка);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РасходнаяНакладная.Водитель КАК Водитель,
| СУММА(РасходнаяНакладная.КолвоЗаявок) КАК КолвоЗаявок
|ИЗ
| Документ.РасходнаяНакладная КАК РасходнаяНакладная
|
|СГРУППИРОВАТЬ ПО
| РасходнаяНакладная.Водитель
|ИТОГИ
| СУММА(КолвоЗаявок)
|ПО
| ОБЩИЕ";
Результат = Запрос.Выполнить();
// Выводим детальные записи
ВыборкаДетали = Результат.Выбрать(ОбходРезультатаЗапроса.Прямой);
Пока ВыборкаДетали.Следующий() Цикл
ОблЭлемент.Параметры.Заполнить(ВыборкаДетали);
ТабДок.Вывести(ОблЭлемент);
КонецЦикла;
// Выводим итог (из общей группировки запроса)
ВыборкаИтог = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Если ВыборкаИтог.Следующий() Тогда
ОблИтого.Параметры.Заполнить(ВыборкаИтог);
ТабДок.Вывести(ОблИтого);
КонецЕсли;
КонецПроцедуры
Важные моменты:
ИТОГИ ПО ОБЩИЕ для получения финальной суммы по всему документу.Выбрать() у объекта метаданных.КАК.Соблюдение этих правил позволит вам создавать быстрые и стабильные отчеты, избегая ошибок исполнения на стороне сервера базы данных.