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