Как в запросе 1С посчитать количество различных документов определенного вида

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

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

В чем заключается проблема и почему возникает погрешность в расчете

Рассмотрим распространенную ситуацию: мы формируем отчет или пишем запрос по регистру, где поле Регистратор имеет составной тип данных. Нам необходимо вывести ресурс, отражающий только уникальные отгрузки. При этом в выборку движений попадают как реализации, так и другие документы.

Часто разработчики пытаются подставить вместо неподходящих документов пустую ссылку или специальное значение, например:


ВЫБОР 
    КОГДА ИсточникДанных.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг 
        ТОГДА ИсточникДанных.Регистратор 
    ИНАЧЕ ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг.ПустаяСсылка) 
КОНЕЦ

или используют значение Неопределено:


КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР 
    КОГДА Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг 
        ТОГДА Регистратор 
    ИНАЧЕ Неопределено 
КОНЕЦ)

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

  1. Значения Неопределено и ПустаяСсылка являются полноценными значениями своих типов данных в платформе 1С.
  2. Агрегатная функция КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) добросовестно считает пустую ссылку или Неопределено как отдельный уникальный элемент.
  3. В результате, если в выборке присутствует хотя бы один документ другого типа, итоговое количество увеличивается ровно на 1.
  4. Попытка вычесть единицу вручную (... - 1) также приводит к ошибке: если в выборке окажутся только реализации и не будет ни одного документа другого типа, отчет вернет заниженное на единицу число.

Правильное решение: использование значения NULL в агрегатных функциях

Выясним причину, по которой стандартные механизмы СУБД и языка запросов 1С работают иначе со значением NULL. В реляционных базах данных и языке запросов платформы агрегатные функции КОЛИЧЕСТВО(Поле) и КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) всегда игнорируют значения NULL.

Если условие в конструкции ВЫБОР не выполняется и ветка ИНАЧЕ не указана (либо явно возвращает NULL), платформа подставляет именно NULL. Такие строки полностью исключаются из подсчета агрегатной функцией.

Посмотрим на пример правильного описания выражения в запросе:


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

Ветку ИНАЧЕ NULL можно опустить, так как по умолчанию конструкция ВЫБОР без ветки ИНАЧЕ возвращает NULL, если ни одно из условий КОГДА не выполнилось:


КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВЫБОР 
    КОГДА Таблица.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг 
        ТОГДА Таблица.Регистратор 
КОНЕЦ)

Применение в Универсальном отчете и Построителе отчета

Разберем по шагам, как применить это решение при программной настройке Универсального отчета (например, в конфигурации УПП 1.3 или других решениях на обычных формах):

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

Посмотрим на готовый код добавления поля-ресурса:


УниверсальныйОтчет.ДобавитьПолеРесурс(
    "КоличествоОтгрузок", 
    "ВЫБОР КОГДА ИсточникДанных.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг ТОГДА ИсточникДанных.Регистратор ИНАЧЕ NULL КОНЕЦ", 
    "Кол-во отгрузок", 
    "Количество(РАЗЛИЧНЫЕ(КоличествоОтгрузок))"
);

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

  1. В выборке присутствуют только реализации: агрегат вернет точное число уникальных документов РеализацияТоваровУслуг.
  2. В выборке присутствуют реализации и другие типы документов: документы других типов трансформируются в NULL, игнорируются функцией подсчета, и результат будет содержать только точное число реализаций без лишней единицы.
  3. В выборке нет ни одной реализации: все строки получат значение NULL, и агрегатная функция вернет корректный результат 0.

Альтернативные варианты реализации

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

  1. Левое соединение с таблицей документов: связываем таблицу движений с таблицей Документ.РеализацияТоваровУслуг по полю Регистратор = РеализацияТоваровУслуг.Ссылка. Для записей с другими регистраторами поле документа автоматически примет значение NULL, после чего к нему применяется КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РеализацияТоваровУслуг.Ссылка).
  2. Отбор на уровне источника: если отчет должен анализировать исключительно отгрузки, накладываем условие фильтрации в секции ГДЕ:
    
    ГДЕ 
        Таблица.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
    
    Это сократит объем обрабатываемых данных на уровне СУБД и повысит производительность формирования отчета.

Важное замечание по производительности: использование КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) по полям составного типа (таким как Регистратор) на больших объемах данных создает дополнительную нагрузку на сервер СУБД из-за необходимости построения промежуточных таблиц и группировок. По возможности ограничивайте период выборки и накладывайте предварительные отборы на уровне исходных данных.

← На главную