Как в 1С найти сотрудников с непарными событиями входа и выхода в системе контроля доступа?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При работе с системами контроля доступа (СКД) часто возникает задача выявления сотрудников, у которых количество событий «Вход» не совпадает с количеством событий «Выход». Это может быть связано с тем, что сотрудник прошел через «черный ход», не приложил карту или возник технический сбой контроллера. Рассмотрим способы решения этой задачи с помощью механизмов запросов 1С.

Метод 1: Проверка на четность общего количества событий

Если нам нужно просто найти идентификаторы (ID) сотрудников, у которых общее число записей за период не является четным (что косвенно указывает на отсутствие пары для какого-то события), можно воспользоваться математическим подходом в запросе. Разберем пример, где мы делим количество записей на 2 и сравниваем результат с целым числом.


ВЫБРАТЬ
    Турникет.ID КАК СотрудникID,
    КОЛИЧЕСТВО(Турникет.ТипСобытия) КАК ВсегоСобытий
ИЗ
    Справочник.Турникет КАК Турникет
ГДЕ
    Турникет.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
СГРУППИРОВАТЬ ПО
    Турникет.ID
ИМЕЮЩИЕ
    (ВЫРАЗИТЬ(КОЛИЧЕСТВО(Турникет.ТипСобытия) / 2 КАК ЧИСЛО(15, 0))) <> (ВЫРАЗИТЬ(КОЛИЧЕСТВО(Турникет.ТипСобытия) / 2 КАК ЧИСЛО(15, 2)))

В данном примере мы используем секцию ИМЕЮЩИЕ для фильтрации результатов группировки. Если результат деления количества записей на 2 с округлением до целого не равен результату без округления (с точностью до 2 знаков), значит, число записей нечетное.

Метод 2: Алгебраический баланс («Вход» против «Выхода»)

Более точный метод — это присвоение каждому типу события числового веса. Например, событию «Вход» присвоим значение 1, а событию «Выход» — значение -1. Если сумма этих значений за период равна нулю, значит, все входы закрыты выходами. Если сумма отлична от нуля, у сотрудника есть «повисшее» событие.

Проанализируем ситуацию на примере следующего запроса:


ВЫБРАТЬ
    Турникет.Сотрудник КАК Сотрудник,
    СУММА(ВЫБОР
            КОГДА Турникет.Событие = ЗНАЧЕНИЕ(Перечисление.ТипыСобытийСКД.Вход)
                ТОГДА 1
            ИНАЧЕ -1
        КОНЕЦ) КАК Баланс
ИЗ
    Справочник.Турникет КАК Турникет
ГДЕ
    Турникет.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
СГРУППИРОВАТЬ ПО
    Турникет.Сотрудник
ИМЕЮЩИЕ
    СУММА(ВЫБОР
            КОГДА Турникет.Событие = ЗНАЧЕНИЕ(Перечисление.ТипыСобытийСКД.Вход)
                ТОГДА 1
            ИНАЧЕ -1
        КОНЕЦ) <> 0

Важный момент: этот способ наглядно показывает «сальдо» посещений. Положительное число означает, что сотрудник вошел, но не вышел. Отрицательное — что зафиксирован выход без входа.

Технические нюансы и оптимизация производительности

При реализации подобных отчетов на больших объемах данных (десятки и сотни тысяч записей) необходимо учитывать несколько критических факторов:

  1. Индексация данных: Если данные хранятся в справочнике, убедитесь, что для реквизитов Сотрудник и Дата установлен признак «Индексировать». В противном случае запрос будет выполнять полное сканирование таблицы (Full Scan), что приведет к длительному ожиданию и блокировкам базы.
  2. Хранение времени: Использование отдельного строкового поля для времени усложняет анализ. Рекомендуется использовать единое поле типа Дата (содержащее и дату, и время). Если же поля разделены, в запросе их придется объединять программно, что делает невозможным использование индексов.
  3. Переходящие смены: Проблема «непарности» часто возникает на границе суток. Если сотрудник зашел в 22:00, а вышел в 06:00 следующего дня, то при отчете строго за один день он попадет в список ошибок. Для решения этой проблемы рекомендуется расширять анализируемый период на несколько часов в обе стороны или использовать механизмы «схлопывания» событий.
  4. Регистры накопления: В долгосрочной перспективе хранить такие данные в справочнике неэффективно. Лучше использовать Регистр накопления (вид «Остатки»), где при входе ресурс увеличивается, а при выходе — уменьшается. Тогда поиск нарушителей сведется к простому получению остатков по регистру.

Реализация на уровне SQL (для внешних источников данных)

Если данные СКД находятся во внешней базе данных, мы можем применить специфические функции SQL для сопоставления строк. Выясним причину расхождений, используя оконные функции, которые позволяют заглянуть в «следующую» запись того же сотрудника:


SELECT 
    EmployeeID, 
    EventTime, 
    EventType
FROM (
    SELECT 
        ID AS EmployeeID, 
        Date + Time AS EventTime, 
        Type AS EventType,
        LEAD(Type) OVER (PARTITION BY ID ORDER BY Date, Time) AS NextEventType
    FROM TurnstileTable
    WHERE Date BETWEEN '2016-12-01' AND '2016-12-01'
) AS Sub
WHERE EventType = NextEventType -- Находит два входа или два выхода подряд

Использование функции LEAD позволяет сравнить текущее событие со следующим. Если тип события повторяется (например, «Вход» и следом снова «Вход»), система мгновенно идентифицирует нарушение последовательности.

← На главную