Как исправить синтаксическую ошибку и правильно подсчитать количество одинаковых записей в регистре сведений?

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

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

Анализ синтаксической ошибки в тексте запроса

Рассмотрим ситуацию, когда при выполнении запроса платформа выдает исключение следующего вида:


{Отчет.ПереченьПриказов.Форма.ФормаОтчета.Форма(65)}: Ошибка при вызове метода контекста (Выполнить)
Результат = Запрос.Выполнить();
по причине:
{(12, 8)}: Синтаксическая ошибка "(ВыходНаПрактику.Место_прохождения_практики)"

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


ВЫБРАТЬ
    ВыходНаПрактику.НомерПриказа,
    ВыходНаПрактику.ДатаИзданияПриказа,
    ВыходНаПрактику.Группа,
    ВыходНаПрактику.Курс,
    ВыходНаПрактику.ДатаНачалаПрактики,
    ВыходНаПрактику.ДатаКонцаПрактики,
    ВыходНаПрактику.ВидПрактики,
    ВыходНаПрактику.Специальность,
    ВыходНаПрактику.Место_прохождения_практики,
    ВыходНаПрактику.ФормаОбучения
    КОЛИЧЕСТВО(ВыходНаПрактику.Место_прохождения_практики) КАК КоличествоМестПрохожденияПрактики 
ИЗ
    РегистрСведений.ВыходНаПрактику КАК ВыходНаПрактику

Выясним причину ошибки: в конце строки с полем ВыходНаПрактику.ФормаОбучения отсутствует разделительная запятая. Парсер языка запросов 1С воспринимает следующее за ним слово как псевдоним текущего поля, а открывающуюся скобку агрегатной функции КОЛИЧЕСТВО(...) — как недопустимую синтаксическую конструкцию. Для устранения ошибки обязательно ставим запятую между полями списка выборки.

Логика группировки записей и подсчета количества

После исправления синтаксиса разработчик может столкнуться с логической ошибкой: колонка КоличествоМестПрохожденияПрактики во всех строках отчета выводит значение 1. Разберем по шагам, почему это происходит.

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

Исправленный пример запроса с выводом в отчет

Посмотрим на пример правильного запроса, где вычисляется количество направлений на практику в разрезе мест прохождения, групп и специальностей:


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

Поиск дублирующихся записей с помощью ИМЕЮЩИЕ

Если задача заключается именно в аудите регистра и поиске ошибочных дублей (строк, повторяющихся несколько раз), используем предложение ИМЕЮЩИЕ. В отличие от ГДЕ, фильтр в ИМЕЮЩИЕ применяется уже после выполнения группировки к результатам агрегатных функций:


ВЫБРАТЬ
    ВыходНаПрактику.Группа КАК Группа,
    ВыходНаПрактику.Место_прохождения_практики КАК МестоПрохождения,
    КОЛИЧЕСТВО(*) КАК КоличествоДублей
ИЗ
    РегистрСведений.ВыходНаПрактику КАК ВыходНаПрактику
СГРУППИРОВАТЬ ПО
    ВыходНаПрактику.Группа,
    ВыходНаПрактику.Место_прохождения_практики
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(*) > 1

Такой запрос вернет исключительно те наборы данных, которые повторяются в регистре более одного раза, исключая уникальные записи.

← На главную