При разработке кадровых отчетов часто возникает необходимость выделить сотрудников, у которых в текущем году намечается юбилей — возраст, кратный 5 (25, 30, 35 лет и так далее). Отдел кадров может потребовать, чтобы такие «юбиляры» выводились в самом начале списка. Давайте рассмотрим, с какими подводными камнями можно столкнуться при решении этой задачи исключительно средствами языка запросов 1С, и разберем эффективные способы ее реализации.
В коде модулей 1С мы привыкли использовать оператор % для получения остатка от деления (например, Возраст % 5 = 0). Однако язык запросов 1С не поддерживает данный оператор. Нам приходится искать обходные пути. Проанализируем несколько рабочих вариантов проверки на кратность прямо в тексте запроса.
Вариант 1: Использование функции ВЫРАЗИТЬ
Самый популярный способ, который часто предлагают разработчики, основан на приведении типов. Мы делим возраст на 5, отбрасываем дробную часть с помощью функции ВЫРАЗИТЬ и сравниваем с результатом обычного деления. Если они равны, значит число делится без остатка.
ВЫБОР
КОГДА ВЫРАЗИТЬ(Таб.Возраст / 5 КАК ЧИСЛО(10, 0)) = (Таб.Возраст / 5)
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ КАК Юбилей
Вариант 2: Надежная математическая формула
Второй паттерн учитывает правила математического округления 1С. Чтобы гарантированно получить остаток от деления в запросе, мы можем вычесть 0.5 перед округлением:
ВЫБОР
КОГДА Возраст - 5 * ВЫРАЗИТЬ((Возраст / 5) - 0.5 КАК ЧИСЛО(15, 0)) = 0
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК ПолеСортировки
Добавив такое поле в запрос, вы легко сможете отсортировать итоговую выборку по убыванию поля ПолеСортировки, тем самым подняв юбиляров в самый верх отчета.
Рассмотрим еще один критически важный аспект. Часто для вычисления возраста используют простую конструкцию:
РАЗНОСТЬДАТ(ФизическоеЛицо.ДатаРождения, &ТекущаяДата, ГОД) КАК Возраст
Эта функция математически «грубая». Она вычитает только годы, игнорируя месяц и день. Например, если сотрудник родился 31 декабря, а отчет формируется 1 января следующего года, функция прибавит ему целый год, хотя фактически прошел только один день. Выясним, как написать условие правильно.
Чтобы получить точный биологический возраст в запросе, нам необходимо вычитать единицу, если день рождения сотрудника в текущем году еще не наступил. Разберем по шагам правильный алгоритм:
РАЗНОСТЬДАТ(ДатаРождения, &ТекущаяДата, ГОД) -
ВЫБОР
КОГДА (МЕСЯЦ(ДатаРождения) > МЕСЯЦ(&ТекущаяДата))
ИЛИ (МЕСЯЦ(ДатаРождения) = МЕСЯЦ(&ТекущаяДата) И ДЕНЬ(ДатаРождения) > ДЕНЬ(&ТекущаяДата))
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК ТочныйВозраст
При усложнении запроса можно столкнуться с ошибкой выполнения. Проанализируем типичную ситуацию:
{(68, 31)}: Неверные параметры "РАЗНОСТЬДАТ"
КОГДА (ВЫРАЗИТЬ(РАЗНОСТЬДАТ(<<?>>ВТДанные.Возраст, &ТекущаяДата, ГОД) / 5 КАК ЧИСЛО(10, 0))) = РАЗНОСТЬДАТ(ВТДанные.Возраст, &ТекущаяДата, ГОД) / 5
Посмотрим на причину: функция РАЗНОСТЬДАТ требует, чтобы оба ее параметра имели тип Дата. Если во временной таблице ВТДанные поле Возраст уже было вычислено ранее и имеет тип Число (например, Год(...) - Год(...)), передача этого числа первым параметром вызовет сбой системы. Будьте внимательны к типам данных при многоуровневых вложенных запросах.
Перегружать текст запроса сложными вычислениями не всегда целесообразно. Давайте посмотрим, какие еще инструменты нам доступны.
СколькоЛет = Цел(Год(ТекущаяДата()) - Год(ТаблицаДанных.ДатаРождения));
Если (СколькоЛет % 5) = 0 Тогда
// Обработка юбиляра
КонецЕсли;
Используя эти методы, вы сможете точно вычислять возраст сотрудников, корректно определять юбиляров и безошибочно сортировать данные в любых кадровых отчетах 1С.