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