Как правильно соединить запросы в ЗУП 2.5 для выбора сотрудников на дату и принятых за период?

Программист 1С v8.3 (Обычные формы) 1С:Зарплата и Управление Персоналом
← На главную

При разработке отчетов в программе 1С:Зарплата и Управление Персоналом 2.5 часто возникает задача: получить список сотрудников, работавших на начало определенного периода, и добавить к ним тех, кто был принят на работу в течение этого периода. Начинающие разработчики часто пытаются решить эту задачу через ПОЛНОЕ СОЕДИНЕНИЕ, что приводит к логическим ошибкам и снижению производительности. В этой статье мы разберем, почему соединение может не работать и как правильно использовать оператор ОБЪЕДИНИТЬ для решения этой задачи.

Анализ проблемы: почему соединение — не лучший выбор?

Рассмотрим ситуацию, с которой столкнулся автор темы. В исходном запросе была попытка соединить две виртуальные таблицы СрезПоследних на разные даты (&д3 и &д2) по полю Сотрудник. Основная сложность заключается в том, что условия фильтрации в секции ГДЕ при использовании ПОЛНОЕ СОЕДИНЕНИЕ работают не так, как ожидается: если условие накладывается на поле из одной таблицы, оно может «отсечь» строки из другой таблицы, превращая полное соединение во внутреннее.

Разберем типичную ошибку в коде:


ВЫБРАТЬ
    РаботникиОрганизацийСрезПоследних.Сотрудник,
    РаботникиОрганизацийСрезПоследних2.Сотрудник КАК Сотрудник2
ИЗ
    РегистрСведений.РаботникиОрганизаций.СрезПоследних(&д3) КАК РаботникиОрганизацийСрезПоследних
    ПОЛНОЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций.СрезПоследних(&д2) КАК РаботникиОрганизацийСрезПоследних2
    ПО РаботникиОрганизацийСрезПоследних.Сотрудник = РаботникиОрганизацийСрезПоследних2.Сотрудник
ГДЕ
    РаботникиОрганизацийСрезПоследних2.Период МЕЖДУ &д3 И &д2

В данном случае, если во второй таблице (на дату &д2) запись не будет найдена или не попадет в период, то вся строка (включая данные из первой таблицы) может быть исключена из результата из-за фильтра в ГДЕ. Именно поэтому опытные разработчики рекомендуют переносить условия из ГДЕ в параметры виртуальной таблицы или использовать объединение.

Решение через ОБЪЕДИНИТЬ: пошаговый разбор

Наиболее эффективным и понятным способом решения данной задачи является использование оператора ОБЪЕДИНИТЬ. Вместо того чтобы пытаться «склеить» данные по горизонтали, мы выбираем два независимых набора данных и выводим их один под другим.

Шаг 1. Выбор сотрудников на начальную дату. Мы берем срез последних на дату &д3 и фильтруем по нужному подразделению.

Шаг 2. Выбор принятых сотрудников за период. Мы берем срез последних на конечную дату &д2, но добавляем условие, что период этой записи (дата кадрового события) находится внутри интересующего нас интервала.

Рассмотрим итоговый код, который был предложен в обсуждении:


ВЫБРАТЬ
    РаботникиОрганизацийСрезПоследних.Сотрудник,
    РаботникиОрганизацийСрезПоследних.ПричинаИзмененияСостояния,
    РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации,
    РаботникиОрганизацийСрезПоследних.Период
ИЗ
    РегистрСведений.РаботникиОрганизаций.СрезПоследних(&д3, ) КАК РаботникиОрганизацийСрезПоследних
ГДЕ
    РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации = &Подр2

ОБЪЕДИНИТЬ  

ВЫБРАТЬ
    РаботникиОрганизацийСрезПоследних.Сотрудник,
    РаботникиОрганизацийСрезПоследних.ПричинаИзмененияСостояния,
    РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации,
    РаботникиОрганизацийСрезПоследних.Период
ИЗ
    РегистрСведений.РаботникиОрганизаций.СрезПоследних(&д2) КАК РаботникиОрганизацийСрезПоследних
ГДЕ
    РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации = &Подр2
    И РаботникиОрганизацийСрезПоследних.Период МЕЖДУ &д3 И &д2
    И РаботникиОрганизацийСрезПоследних.ПричинаИзмененияСостояния = &ПричинаИзмененияСостояния

Оптимизация производительности: параметры виртуальных таблиц

Хотя предложенное выше решение рабочее, его можно значительно ускорить. В 1С использование секции ГДЕ для виртуальных таблиц (таких как СрезПоследних) считается неоптимальным. Проанализируем причину: при использовании ГДЕ система сначала получает все последние записи из базы данных, а потом фильтрует их. Если в базе десятки тысяч сотрудников, это создаст колоссальную нагрузку.

Правильный подход: передавать фильтры напрямую в параметры виртуальной таблицы. В этом случае SQL-запрос будет содержать фильтрацию сразу при выборке данных.

Оптимизируем наш запрос:


ВЫБРАТЬ
    Работники.Сотрудник,
    Работники.ПричинаИзмененияСостояния,
    Работники.ПодразделениеОрганизации,
    Работники.Период
ИЗ
    РегистрСведений.РаботникиОрганизаций.СрезПоследних(&д3, ПодразделениеОрганизации = &Подр2) КАК Работники

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Работники.Сотрудник,
    Работники.ПричинаИзмененияСостояния,
    Работники.ПодразделениеОрганизации,
    Работники.Период
ИЗ
    РегистрСведений.РаботникиОрганизаций.СрезПоследних(&д2, ПодразделениеОрганизации = &Подр2 
        И ПричинаИзмененияСостояния = &ПричинаИзмененияСостояния) КАК Работники
ГДЕ
    Работники.Период МЕЖДУ &д3 И &д2

Обратите внимание на использование ОБЪЕДИНИТЬ ВСЕ вместо ОБЪЕДИНИТЬ. Оператор ОБЪЕДИНИТЬ выполняет проверку на уникальность строк (аналог DISTINCT), что требует дополнительных ресурсов сервера. Если вы уверены, что наборы данных не пересекаются или дубликаты допустимы, всегда выбирайте ОБЪЕДИНИТЬ ВСЕ.

Важные технические нюансы работы в ЗУП 2.5

При работе с кадровыми данными в ЗУП 2.5 следует учитывать несколько критических моментов, которые могут повлиять на корректность отчета:

  1. Проверка состояния «Уволен»: Если ваша задача — получить список работающих сотрудников, обязательно добавьте фильтр по состоянию. Сотрудник может попасть в СрезПоследних на дату &д2, но его последнее состояние будет «Увольнение». В таком случае он не должен отображаться в списке активного персонала.
  2. Работа с границами периода: В 1С время имеет значение. Если вы используете дату без указания времени, она воспринимается как начало дня (00:00:00). Если документ приема был проведен в 00:00:00 той же секундой, он может не попасть в срез. Для максимально точных результатов рекомендуется использовать объект Граница с видом ВидГраницы.Включая.
  3. Специфика виртуальной таблицы: Помните, что СрезПоследних на дату &д2 с условием Период МЕЖДУ &д3 И &д2 покажет только тех сотрудников, чье последнее изменение в регистре произошло именно в этот период. Если сотрудника приняли, а потом через день перевели в другое подразделение (внутри одного периода), СрезПоследних покажет только запись о переводе.

Использование временных таблиц

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

Во-первых, мы создаем временную таблицу ВТ_Сотрудники, куда помещаем результат нашего объединения. Во-вторых, в основном запросе мы просто выбираем данные из этой таблицы и соединяем их с другими регистрами (например, ФИОФизЛиц или ДолжностиОрганизаций).

Это делает код читаемым, облегчает отладку в консоли запросов и позволяет системе 1С построить наиболее оптимальный план выполнения запроса на уровне SQL-сервера.

← На главную