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

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

В практике разработчика 1С часто возникает задача: получить из базы данных не просто список всех документов, а только самые свежие записи для каждого конкретного объекта (например, последнюю реализацию по каждому контрагенту). На первый взгляд задача кажется простой, но новички часто допускают фундаментальную ошибку в логике работы оператора СГРУППИРОВАТЬ ПО. Разберем подробно, почему стандартный подход "в лоб" не работает и как реализовать этот запрос правильно и эффективно.

Анализ типичной ошибки группировки

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


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

Почему это не работает: Оператор СГРУППИРОВАТЬ ПО объединяет записи с одинаковыми значениями в указанных полях. Поле Регистратор.Ссылка является уникальным идентификатором документа. Если мы включаем ссылку в группировку, СУБД создает отдельную группу для каждого конкретного документа. В результате функция МАКСИМУМ(Дата) вычисляется не среди всех документов контрагента, а внутри группы из одного-единственного документа. Мы получаем обычный список всех реализаций, а не "последнюю".

Правильный алгоритм: Двухэтапный запрос

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

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

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


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

Шаг 2: Соединение временной таблицы с исходными данными

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


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

Важный нюанс: Момент времени вместо Даты

В системе 1С за одну и ту же секунду может быть проведено несколько документов. Если мы будем искать последний документ только по дате, запрос может вернуть несколько ссылок для одного контрагента (если у них совпадает время до секунды). Чтобы избежать этого, рекомендуется использовать МоментВремени.

МоментВремени — это объект, объединяющий дату и ссылку на документ. Он гарантирует уникальную последовательность событий в базе данных. Проанализируем, как изменится наш запрос:

  1. В первом запросе (ВТ) мы будем выбирать МАКСИМУМ(РасчетыСКонтрагентами.Регистратор.МоментВремени).
  2. Во втором запросе соединение будет происходить по полю МоментВремени.

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

Оптимизация производительности: "Разыменование ссылок"

Разберем еще один критический момент — обращение через точку к реквизитам ссылочных полей, например, Регистратор.Организация.Наименование. В языке запросов 1С каждое такое обращение превращается в неявное ЛЕВОЕ СОЕДИНЕНИЕ (Left Join) на уровне СУБД.

Рассмотрим рекомендации по оптимизации:

Итоговый пример оптимального кода

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


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

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

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

← На главную