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