Как получить данные табличной части последнего документа по каждому контрагенту

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

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

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

Вариант 1. Классический запрос с вложенными подзапросами

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

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


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

Разберем по шагам, что происходит в этом коде:

  1. Самый глубокий вложенный запрос находит для каждого Контрагента его самую позднюю Дату документа. Мы также добавили условие Проведен = ИСТИНА, чтобы не учитывать черновики или помеченные на удаление объекты.
  2. Второй уровень вложенности решает проблему «одинаковых секунд». Если по одному контрагенту в одну и ту же секунду создано два документа, СУБД должна выбрать один из них. Используя МАКСИМУМ(Ссылка), мы гарантируем, что для каждого контрагента останется ровно одна ссылка.
  3. Итоговый запрос выполняет соединение полученного списка ссылок с табличной частью Товары.

Вариант 2. Оптимизация с использованием временных таблиц

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

Для оптимизации мы рекомендуем использовать временные таблицы. Рассмотрим подробнее этот алгоритм:

Шаг 1. Получаем максимальные даты и помещаем их во временную таблицу.


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

Шаг 2. Получаем конкретные ссылки на документы.


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

Шаг 3. Финальная выборка данных из табличной части.


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

Такой подход работает значительно быстрее за счет использования индексов во временных таблицах и более простого плана выполнения для SQL-сервера.

Важные нюансы и рекомендации

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

  1. Момент времени: В 1С документы располагаются на временной оси не только по дате, но и по ссылке. В запросах мы эмулируем МоментВремени через связку МАКСИМУМ(Дата) + МАКСИМУМ(Ссылка). Это стандартный и наиболее надежный способ в языке запросов.
  2. Левое vs Внутреннее соединение: Если вы используете ЛЕВОЕ СОЕДИНЕНИЕ с табличной частью (как в наших примерах), то контрагенты, у которых последний документ оказался пустым (без строк в табличной части), все равно попадут в результат с пустыми значениями номенклатуры. Если такие записи вам не нужны — используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ.
  3. Производительность: Если эта задача выполняется крайне часто (например, при каждом открытии динамического списка), рассмотрите вариант создания Регистра сведений. В такой регистр можно записывать ссылку на последний документ контрагента в момент проведения. Тогда запрос станет элементарным: просто выборка из регистра по измерению Контрагент.
  4. Группировка строк: Помните, что в одном документе может быть несколько строк с одной и той же номенклатурой. Если вам нужно получить суммарный итог по последнему документу, не забудьте добавить СГРУППИРОВАТЬ ПО в финальном запросе и использовать агрегатные функции, такие как СУММА(Количество).

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

← На главную