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