Как в запросе 1С получить ответственное лицо или срез последних на каждую дату документа

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

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

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

Почему нельзя использовать простое соединение

Рассмотрим ситуацию: документ «Поступление товаров и услуг» создан 15.08.2018 в 11:23:47. В регистре сведений запись об ответственном была внесена 01.08.2018 в 09:00:00. Если мы попытаемся применить ЛЕВОЕ СОЕДИНЕНИЕ по условию Поступление.Дата = Регистр.Период, система не найдет соответствия, и поле ответственного останется пустым (NULL). Нам же нужно получить запись, которая была актуальна на момент или непосредственно до даты документа.

Метод 1: Трехэтапный запрос с использованием временных таблиц

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

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

Сначала мы выберем все интересующие нас документы (или строки таблицы поступлений) во временную таблицу. Нам важно сохранить уникальный идентификатор строки или сам документ и его дату.


ВЫБРАТЬ
    Поступление.Ссылка КАК Документ,
    Поступление.Дата КАК ДатаДокумента
ПОМЕСТИТЬ ВТ_Документы
ИЗ
    Документ.ПоступлениеТоваровУслуг КАК Поступление
ГДЕ
    Поступление.Дата МЕЖДУ &НачалоПериода И &КонецПериода
;

Шаг 2: Поиск максимально близкой даты в регистре

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


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

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

На заключительном этапе мы соединяем исходную таблицу документов с таблицей максимально найденных дат, а затем — с самим регистром сведений. Это позволяет нам вытащить ответственное лицо, соответствующее найденному моменту времени.


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

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

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

Выясним, как это настроить:

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

При таком подходе СКД сама выполнит подзапрос для каждой строки основного списка, обеспечивая получение корректного ответственного на дату документа.

Важные нюансы и оптимизация

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

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

Индексация: Для быстрого выполнения условия Регистр.Период <= Таблица.Дата крайне важно, чтобы поле Период было индексировано. В периодических регистрах сведений 1С это происходит автоматически, однако при использовании измерений (например, Организация), убедитесь, что они также участвуют в индексах для ускорения поиска.

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

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

← На главную