Разработка кадровых отчетов — одна из классических задач, с которой сталкивается любой начинающий разработчик в среде «1С:Предприятие 8». На первый взгляд задача вывода вакантных должностей кажется тривиальной: достаточно создать периодический регистр сведений, записывать туда изменения и получать актуальное состояние. Однако именно здесь новичков подстерегает опасная архитектурная ловушка, связанная с неправильным проектированием измерений и ресурсов регистра сведений.
В этой статье мы подробно разберем, почему типовые подходы «в лоб» часто приводят к неверным данным в отчетах, проанализируем разницу между измерениями и ресурсами регистра, а также разработаем правильный и оптимизированный запрос для получения актуальных вакансий на любую дату.
Рассмотрим ситуацию, с которой часто сталкиваются начинающие разработчики. Был создан справочник Должности и периодический регистр сведений ШтатноеРасписание со следующей структурой:
Должность (тип СправочникСсылка.Должности), Вакантное (тип Булево).Сотрудник (тип СправочникСсылка.Сотрудники).При такой структуре в регистр записывались изменения. Например:
Вакантное = ИСТИНА, сотрудник пустой).Вакантное = ЛОЖЬ, сотрудник «Иванов И.И.»).При попытке построить отчет с использованием виртуальной таблицы СрезПоследних и условием отбора по флагу Вакантное = ИСТИНА система все равно выводит должность «Инженер» как вакантную на текущую дату. Выясним, почему так происходит.
Дело в том, что измерения регистра сведений определяют уникальность записей. В системе 1С уникальность записи в периодическом регистре проверяется по комбинации полей: Период + Измерение1 + Измерение2 + ....
Когда мы делаем поле Вакантное измерением, для платформы записи с разными значениями этого флага становятся абсолютно независимыми ветками истории. Система считает, что в регистре хранятся две разные сущности:
Когда виртуальная таблица СрезПоследних обрабатывает эти данные, она берет последнюю запись по каждой уникальной комбинации измерений. В результате мы получаем две актуальные строки:
Затем, когда в отчете срабатывает фильтр ГДЕ Вакантное = ИСТИНА, система просто отсекает строку за 3 августа и оставляет в результате «устаревшую» запись от 1 августа. Отчет показывает некорректную информацию.
Чтобы избежать подобных ошибок, необходимо запомнить важное правило проектирования баз данных в 1С: в измерения регистра нужно выносить только те разрезы учета, по которым нам необходимо получать независимую историю изменений. Все качественные и количественные характеристики состояния (такие как статус «Вакантно», «Активно», «Заблокировано» или имя конкретного сотрудника) должны быть ресурсами или вообще вычисляться динамически.
Посмотрим на правильную структуру регистра сведений ШтатноеРасписание:
Должность (тип СправочникСсылка.Должности). У нас должна быть только одна уникальная история изменений по каждой должности.Сотрудник (тип СправочникСсылка.Сотрудники).При такой структуре нам даже не нужен дополнительный флаг Вакантное. Сама бизнес-логика подсказывает: если на должности никто не работает (поле Сотрудник пустое), значит, эта должность вакантна.
История изменений в регистре теперь выглядит так:
Должность: «Инженер», Сотрудник: Пустая ссылка.Должность: «Инженер», Сотрудник: «Иванов И.И.».Теперь по измерению Должность («Инженер») существует строго одна цепочка событий. Срез последних на любую дату после 3 августа вернет ровно одну запись: «Инженер — Иванов И.И.».
Теперь разберем, как правильно написать запрос к новой структуре регистра для получения списка только вакантных должностей. Здесь тоже есть крайне важный нюанс работы с виртуальными таблицами.
Рассмотрим структуру запроса:
ВЫБРАТЬ
ШтатноеРасписаниеСрезПоследних.Должность КАК Должность,
ШтатноеРасписаниеСрезПоследних.Сотрудник КАК Сотрудник
ИЗ
РегистрСведений.ШтатноеРасписание.СрезПоследних(&Период, ) КАК ШтатноеРасписаниеСрезПоследних
ГДЕ
ШтатноеРасписаниеСрезПоследних.Sотрудник = ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)
Критически важный момент: Обратите внимание, где именно наложено условие отбора по пустому сотруднику. Оно находится в секции ГДЕ основного запроса, а не в параметрах виртуальной таблицы СрезПоследних.
Проанализируем, почему нельзя писать условие отбора по ресурсу внутри параметров виртуальной таблицы, например: СрезПоследних(&Период, Сотрудник = ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка)).
Если наложить условие во втором параметре виртуальной таблицы, платформа сначала отфильтрует физическую таблицу регистра, выкинув из нее все записи, где сотрудник заполнен. И только после этой фильтрации начнет рассчитывать срез последних. В нашем примере запись от 3 августа (где указан Иванов) будет проигнорирована еще на этапе предварительного отбора, и система вернет нам срез последних на основании записи от 1 августа (где сотрудник был пустой). В итоге мы опять получим неверный результат: занятый Инженер отобразится в отчете как вакантный.
Правильный алгоритм работы запроса должен быть следующим:
ГДЕ, отсечь те записи, в которых ресурс Сотрудник оказался заполнен.В реальных бизнес-приложениях учет штатных единиц устроен значительно сложнее, так как простая схема «одна должность — один сотрудник» не покрывает потребности средних и крупных предприятий. Рассмотрим основные отличия промышленной архитектуры от учебной:
КоличествоСтавок (сколько утверждено по плану) и ЗанятоСтавок (сколько фактически занято). Формула вакансий в таком случае выглядит как разность: КоличествоСтавок - ЗанятоСтавок > 0.При создании отчетов на схеме компоновки данных (СКД) начинающие разработчики часто совершают ошибку, полностью отключая выбор периода, чтобы «отчет всегда показывал данные на текущий момент». Однако на практике руководству и кадровой службе регулярно требуется ретроспективный анализ (например, получить список вакансий на начало прошлого квартала).
Правильным решением будет:
&Период доступным в настройках запроса виртуальной таблицы.Период задать выражение КонецПериода(&Период, "ДЕНЬ") или установить использование по умолчанию текущей даты (функция ТекущаяДата()), чтобы при открытии отчета пользователь сразу видел актуальное состояние, но сохранял возможность выбрать любой другой день в прошлом.Используя описанные правила проектирования и структуру запросов, вы сможете создавать надежные, быстродействующие и легко масштабируемые кадровые отчеты на платформе «1С:Предприятие 8».