Как выбрать документ с максимальной датой по каждому владельцу в запросе 1С?

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

При разработке отчетов и обработок в платформе 1С часто возникает задача получить по каждому физическому лицу или контрагенту (владельцу) актуальный документ — то есть запись с максимальной датой действия. Рассмотрим по шагам, как правильно составить такой запрос, с какими подводными камнями можно столкнуться и как избежать дублирования строк.

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

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


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

При использовании такой схемы возникают две серьезные проблемы:

  1. Низкая производительность: СУБД не может проиндексировать данные внутри секции ПО при соединении с вложенным запросом. На больших объемах данных это приводит кполному сканированию таблицы (Full Scan) и падению скорости выполнения.
  2. Задвоение записей при одинаковых датах: Если у одного владельца вводятся два разных документа с одинаковой максимальной датой (например, 01.02.2022), условие соединения по дате вернет обе записи. Итоговый результат раздвоится.

Особенности языка запросов 1С

В языке запросов 1С отсутствуют оконные аналитические функции типа ROW_NUMBER() OVER (...), а конструкция ВЫБРАТЬ ПЕРВЫЕ 1 применяется ко всему итоговому результату запроса, а не к каждой группе по владельцу отдельно. По этой причине выбор одной актуальной записи требует грамотного сочетания временных таблиц и агрегатных функций.

Оптимальное решение с временными таблицами

Проанализируем решение, которое оптимизирует нагрузку на СУБД и гарантирует получение ровно одной записи по каждому владельцу.

Шаги алгоритма:

  1. Получить максимальную дату для каждого владельца во временной таблице.
  2. Сгруппировать записи с одинаковой датой по владельцу и применить функцию МАКСИМУМ(Ссылка) — поскольку Ссылка всегда уникальна, платформа выберет ровно один документ.
  3. Проиндексировать временную таблицу по ключу соединения.
  4. Соединить полученную временную таблицу с исходным справочником по полю Ссылка.

Рассмотрим пример реализации такого запроса:


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

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

Настройка приоритета документов

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


ВЫБРАТЬ
    Документы.Владелец КАК Владелец,
    Документы.Ссылка КАК Ссылка,
    ВЫБОР
        КОГДА Документы.ВидДокумента = ЗНАЧЕНИЕ(Справочник.ВидыДокументов.Паспорт) ТОГДА 1
        ИНАЧЕ 2
    КОНЕЦ КАК Приоритет
ПОМЕСТИТЬ ВТ_ДокументыСПриоритетом
ИЗ
    Справочник.Документы КАК Документы
;

Далее вычисляется минимальный (или максимальный) приоритет для каждого владельца и выполняются последующие соединения.

Архитектурная альтернатива: регистры сведений

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

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

← На главную