Как в одном запросе 1С получить данные из регистра сведений на разные даты для каждой строки

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

В практике разработчика 1С часто возникает задача: получить данные из периодического регистра сведений (например, должность или подразделение сотрудника) не на одну общую дату, а на разные даты, соответствующие каждой строке исходного документа или таблицы. Классическая виртуальная таблица СрезПоследних здесь не поможет напрямую, так как она принимает в качестве параметра Период только одно значение на весь запрос.

Разберем, как обойти это ограничение и эффективно решить задачу, используя возможности языка запросов и механизмы платформы 1С. Мы проанализируем ситуацию, когда у нас есть список сотрудников с разными датами событий, и нам нужно вытащить их актуальные данные из регистра РаботникиОрганизаций.

Метод 1: Использование временных таблиц и физических таблиц регистра

Это самый надежный и производительный способ решения задачи «в лоб». Мы не будем использовать виртуальную таблицу СрезПоследних, а самостоятельно сконструируем её аналог для каждой строки. Рассмотрим этот процесс по шагам.

Шаг 1: Подготовка исходных данных

Для начала нам нужно собрать все пары «Сотрудник — Дата», для которых требуются данные. Поместим их во временную таблицу, чтобы в дальнейшем было удобно выполнять соединения. Проанализируем пример получения данных из табличной части документа:


ВЫБРАТЬ
    КадровыйПриказСотрудники.Сотрудник КАК Сотрудник,
    КадровыйПриказСотрудники.ДатаСобытия КАК ДатаСобытия,
    КадровыйПриказСотрудники.Ссылка КАК ДокументСсылка
ПОМЕСТИТЬ ВТ_ИсходныеДанные
ИЗ
    Документ.КадровыйПриказ.Сотрудники КАК КадровыйПриказСотрудники
ГДЕ
    КадровыйПриказСотрудники.Ссылка = &Ссылка
;

Шаг 2: Поиск максимального периода в регистре

Теперь нам нужно определить для каждого сотрудника и каждой даты события ту самую «последнюю» запись в регистре сведений, которая была актуальна на этот момент. Мы соединяем нашу временную таблицу с физической таблицей регистра по условию: период в регистре должен быть меньше или равен нашей целевой дате.


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

Шаг 3: Получение финальных данных

На последнем этапе мы соединяем таблицу с найденными максимальными периодами обратно с физической таблицей регистра, чтобы получить значения ресурсов (должность, подразделение и т.д.).


ВЫБРАТЬ
    ВТ_МаксимальныеДаты.Сотрудник,
    ВТ_МаксимальныеДаты.ДатаСобытия,
    ВТ_МаксимальныеДаты.ДокументСсылка,
    РаботникиОрганизаций.Подразделение,
    РаботникиОрганизаций.Должность
ИЗ
    ВТ_МаксимальныеДаты КАК ВТ_МаксимальныеДаты
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
        ПО ВТ_МаксимальныеДаты.Сотрудник = РаботникиОрганизаций.Сотрудник
            И ВТ_МаксимальныеДаты.АктуальныйПериод = РаботникиОрганизаций.Период
;

Проблема дублей: несколько записей на одну секунду

Важно помнить, что в 1С возможна ситуация, когда в одну и ту же секунду по одному сотруднику внесено две записи в регистр. В этом случае соединение только по полю Период приведет к «размножению» строк в результате запроса. Выясним причину: СУБД найдет две записи с одинаковым максимальным периодом и подставит обе.

Чтобы этого избежать, в Шаге 2 нужно искать не только МАКСИМУМ(Период), но и дополнительный уникальный ключ. Если периодичность регистра установлена «В пределах секунды», то таким ключом может выступать НомерСтроки (если записи в рамках одного регистратора) или МоментВремени регистратора.

Рассмотрим доработанный вариант поиска уникальной записи:

  1. Сначала находим максимальный период.
  2. Затем для этого периода находим максимальный регистратор или номер строки.
  3. И только потом соединяем с данными.

Метод 2: Использование Системы компоновки данных (СКД)

Если ваша задача — построить отчет или вывести данные в форму, то механизм СКД позволяет решить проблему гораздо элегантнее без написания сложных вложенных запросов. Посмотрим на пример реализации через связи наборов данных.

Алгоритм действий следующий:

  1. Создаем первый набор данных — запрос, который выбирает основные данные (сотрудников и их даты из документа).
  2. Создаем второй набор данных — запрос к виртуальной таблице СрезПоследних регистра. В параметрах виртуальной таблицы указываем стандартный параметр &Период.
  3. Переходим на закладку Связи наборов данных.
  4. Связываем первый набор со вторым по полю Сотрудник.
  5. Самое важное: в колонке «Параметры связи» указываем, что поле ДатаСобытия из первого набора данных должно передаваться в параметр Период второго набора данных.

При таком подходе платформа 1С самостоятельно выполнит отдельный подзапрос для каждой строки первого набора, подставляя нужную дату в срез последних. Это значительно упрощает разработку и минимизирует риск ошибок в логике соединений.

Оптимизация и производительность

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

Рассмотрим пример использования ЕСТЬNULL и типичную ошибку при работе с NULL в условиях:


ВЫБРАТЬ
    ВТ.Сотрудник,
    ЕСТЬNULL(Р.Подразделение, "Не определено") КАК Подразделение
ИЗ
    ВТ_Данные КАК ВТ
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Подразделения КАК Р
    ПО ВТ.Сотрудник = Р.Сотрудник

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

← На главную