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