При составлении отчетов на платформе 1С:Предприятие разработчики нередко сталкиваются с необходимостью сгруппировать строки регистра сведений и подсчитать число одинаковых значений. В процессе написания текста запроса вручную легко допустить синтаксическую ошибку или построить неверную логику группировки, из-за которой количество всегда будет равно единице. Разберем типичные ошибки при использовании агрегатных функций и рассмотрим шаги по их устранению.
Рассмотрим ситуацию, когда при выполнении запроса платформа выдает исключение следующего вида:
{Отчет.ПереченьПриказов.Форма.ФормаОтчета.Форма(65)}: Ошибка при вызове метода контекста (Выполнить)
Результат = Запрос.Выполнить();
по причине:
{(12, 8)}: Синтаксическая ошибка "(ВыходНаПрактику.Место_прохождения_практики)"
Проанализируем фрагмент запроса, приведший к сбою:
ВЫБРАТЬ
ВыходНаПрактику.НомерПриказа,
ВыходНаПрактику.ДатаИзданияПриказа,
ВыходНаПрактику.Группа,
ВыходНаПрактику.Курс,
ВыходНаПрактику.ДатаНачалаПрактики,
ВыходНаПрактику.ДатаКонцаПрактики,
ВыходНаПрактику.ВидПрактики,
ВыходНаПрактику.Специальность,
ВыходНаПрактику.Место_прохождения_практики,
ВыходНаПрактику.ФормаОбучения
КОЛИЧЕСТВО(ВыходНаПрактику.Место_прохождения_практики) КАК КоличествоМестПрохожденияПрактики
ИЗ
РегистрСведений.ВыходНаПрактику КАК ВыходНаПрактику
Выясним причину ошибки: в конце строки с полем ВыходНаПрактику.ФормаОбучения отсутствует разделительная запятая. Парсер языка запросов 1С воспринимает следующее за ним слово как псевдоним текущего поля, а открывающуюся скобку агрегатной функции КОЛИЧЕСТВО(...) — как недопустимую синтаксическую конструкцию. Для устранения ошибки обязательно ставим запятую между полями списка выборки.
После исправления синтаксиса разработчик может столкнуться с логической ошибкой: колонка КоличествоМестПрохожденияПрактики во всех строках отчета выводит значение 1. Разберем по шагам, почему это происходит.
Место_прохождения_практики в рамках специальности или группы), из списков ВЫБРАТЬ и СГРУППИРОВАТЬ ПО необходимо исключить уникальные реквизиты (номера приказов, точные даты).КОЛИЧЕСТВО(*). Выражение КОЛИЧЕСТВО(Поле) пропускает строки, где значение равно NULL, а конструкция СУММА(1) нарушает стандарты и на больших выборках может приводить к арифметическому переполнению.Посмотрим на пример правильного запроса, где вычисляется количество направлений на практику в разрезе мест прохождения, групп и специальностей:
&НаСервереБезКонтекста
Процедура ЗаполнитьТабДок(ТабДок, ДатаНачала, ДатаКонца, Группа)
ТабДок.АвтоМасштаб = Истина;
Макет = Отчеты.ПереченьПриказов.ПолучитьМакет("Макет");
ОблШапка = Макет.ПолучитьОбласть("Шапка");
ОблЭлемент = Макет.ПолучитьОбласть("Элемент");
ТабДок.Очистить();
ТабДок.Вывести(ОблШапка);
ТекстЗапроса =
"ВЫБРАТЬ
| ВыходНаПрактику.Группа КАК Группа,
| ВыходНаПрактику.Специальность КАК Специальность,
| ВыходНаПрактику.ВидПрактики КАК ВидПрактики,
| ВыходНаПрактику.Место_прохождения_практики КАК МестоПрохожденияПрактики,
| КОЛИЧЕСТВО(*) КАК КоличествоМест
|ИЗ
| РегистрСведений.ВыходНаПрактику КАК ВыходНаПрактику
|ГДЕ
| ВыходНаПрактику.ДатаНачалаПрактики >= &ДатаНачала
| И ВыходНаПрактику.ДатаКонцаПрактики <= &ДатаКонца";
// Оптимизация: избегаем использования ИЛИ с параметром в ГДЕ
Если ЗначениеЗаполнено(Группа) Тогда
ТекстЗапроса = ТекстЗапроса + "
| И ВыходНаПрактику.Группа = &Группа";
КонецЕсли;
ТекстЗапроса = ТекстЗапроса + "
|СГРУППИРОВАТЬ ПО
| ВыходНаПрактику.Группа,
| ВыходНаПрактику.Специальность,
| ВыходНаПрактику.ВидПрактики,
| ВыходНаПрактику.Место_прохождения_практики
|
|УПОРЯДОЧИТЬ ПО
| ВыходНаПрактику.Группа,
| КоличествоМест УБЫВ";
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаКонца", ДатаКонца);
Если ЗначениеЗаполнено(Группа) Тогда
Запрос.УстановитьПараметр("Группа", Группа);
КонецЕсли;
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
ОблЭлемент.Параметры.Группа = Выборка.Группа;
ОблЭлемент.Параметры.Специальность = Выборка.Специальность;
ОблЭлемент.Параметры.ВидПрактики = Выборка.ВидПрактики;
ОблЭлемент.Параметры.МестоПрохожденияПрактики = Выборка.МестоПрохожденияПрактики;
ОблЭлемент.Параметры.КолВо = Выборка.КоличествоМест;
ТабДок.Вывести(ОблЭлемент);
КонецЦикла;
КонецПроцедуры
Если задача заключается именно в аудите регистра и поиске ошибочных дублей (строк, повторяющихся несколько раз), используем предложение ИМЕЮЩИЕ. В отличие от ГДЕ, фильтр в ИМЕЮЩИЕ применяется уже после выполнения группировки к результатам агрегатных функций:
ВЫБРАТЬ
ВыходНаПрактику.Группа КАК Группа,
ВыходНаПрактику.Место_прохождения_практики КАК МестоПрохождения,
КОЛИЧЕСТВО(*) КАК КоличествоДублей
ИЗ
РегистрСведений.ВыходНаПрактику КАК ВыходНаПрактику
СГРУППИРОВАТЬ ПО
ВыходНаПрактику.Группа,
ВыходНаПрактику.Место_прохождения_практики
ИМЕЮЩИЕ
КОЛИЧЕСТВО(*) > 1
Такой запрос вернет исключительно те наборы данных, которые повторяются в регистре более одного раза, исключая уникальные записи.