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