В практике разработчика 1С часто возникает задача: получить актуальные данные из последних документов для списка контрагентов. Например, это может быть последняя цена закупки товара, дата последней отгрузки или состав последней заявки. Основная сложность здесь заключается в том, что обычная группировка по контрагенту позволяет получить только максимальную дату, но не позволяет напрямую «вытащить» данные из табличной части именно этого документа.
В этой статье мы подробно разберем, как построить эффективный запрос, учитывающий нюансы платформы 1С, и обеспечивающий корректный результат даже в сложных случаях.
Рассмотрим первый подход, который часто используется для решения данной задачи. Основная идея заключается в трехступенчатом выборе данных. Проанализируем ситуацию: нам нужно сначала найти максимальную дату документа для каждого контрагента, затем найти конкретную ссылку на документ (на случай, если документов в одну секунду было несколько), и только потом соединиться с его табличной частью.
Посмотрим на пример реализации такого запроса:
"ВЫБРАТЬ
| ПоследниеСсылки.Контрагент КАК Контрагент,
| ПоследниеСсылки.Ссылка КАК Ссылка,
| РеализацияТовары.Номенклатура КАК Номенклатура,
| РеализацияТовары.Количество КАК Количество
|ИЗ
| (ВЫБРАТЬ
| МаксимальныеДаты.Контрагент КАК Контрагент,
| МАКСИМУМ(Реализация.Ссылка) КАК Ссылка
| ИЗ
| (ВЫБРАТЬ
| Реализация.Контрагент КАК Контрагент,
| МАКСИМУМ(Реализация.Дата) КАК Дата
| ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
| ГДЕ
| Реализация.Проведен = ИСТИНА
| СГРУППИРОВАТЬ ПО
| Реализация.Контрагент) КАК МаксимальныеДаты
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
| ПО МаксимальныеДаты.Контрагент = Реализация.Контрагент
| И МаксимальныеДаты.Дата = Реализация.Дата
| СГРУППИРОВАТЬ ПО
| МаксимальныеДаты.Контрагент) КАК ПоследниеСсылки
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
| ПО ПоследниеСсылки.Ссылка = РеализацияТовары.Ссылка"
Разберем по шагам, что происходит в этом коде:
Контрагента его самую позднюю Дату документа. Мы также добавили условие Проведен = ИСТИНА, чтобы не учитывать черновики или помеченные на удаление объекты.МАКСИМУМ(Ссылка), мы гарантируем, что для каждого контрагента останется ровно одна ссылка.Товары.Если в вашей базе данных сотни тысяч документов РеализацияТоваровУслуг, использование вложенных запросов может привести к существенному замедлению работы системы. Это происходит потому, что планировщик SQL не всегда может эффективно проиндексировать промежуточные результаты внутри одного большого запроса. Выясним причину: при глубокой вложенности сложно предсказать объем промежуточных данных.
Для оптимизации мы рекомендуем использовать временные таблицы. Рассмотрим подробнее этот алгоритм:
Шаг 1. Получаем максимальные даты и помещаем их во временную таблицу.
"ВЫБРАТЬ
| Док.Контрагент КАК Контрагент,
| МАКСИМУМ(Док.Дата) КАК Дата
|ПОМЕСТИТЬ ВТ_МаксДаты
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Док
|ГДЕ
| Док.Проведен
|СГРУППИРОВАТЬ ПО
| Док.Контрагент
|ИНДЕКСИРОВАТЬ ПО
| Контрагент, Дата"
Шаг 2. Получаем конкретные ссылки на документы.
"ВЫБРАТЬ
| ВТ_МаксДаты.Контрагент КАК Контрагент,
| МАКСИМУМ(Реализация.Ссылка) КАК Ссылка
|ПОМЕСТИТЬ ВТ_ПоследниеДокументы
|ИЗ
| ВТ_МаксДаты КАК ВТ_МаксДаты
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
| ПО ВТ_МаксДаты.Контрагент = Реализация.Контрагент
| И ВТ_МаксДаты.Дата = Реализация.Дата
|СГРУППИРОВАТЬ ПО
| ВТ_МаксДаты.Контрагент
|ИНДЕКСИРОВАТЬ ПО
| Ссылка"
Шаг 3. Финальная выборка данных из табличной части.
"ВЫБРАТЬ
| ВТ_ПоследниеДокументы.Контрагент,
| РеализацияТовары.Номенклатура,
| РеализацияТовары.Количество,
| РеализацияТовары.Цена
|ИЗ
| ВТ_ПоследниеДокументы КАК ВТ_ПоследниеДокументы
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
| ПО ВТ_ПоследниеДокументы.Ссылка = РеализацияТовары.Ссылка"
Такой подход работает значительно быстрее за счет использования индексов во временных таблицах и более простого плана выполнения для SQL-сервера.
Проанализируем несколько важных моментов, которые могут повлиять на корректность ваших данных:
МоментВремени через связку МАКСИМУМ(Дата) + МАКСИМУМ(Ссылка). Это стандартный и наиболее надежный способ в языке запросов.ЛЕВОЕ СОЕДИНЕНИЕ с табличной частью (как в наших примерах), то контрагенты, у которых последний документ оказался пустым (без строк в табличной части), все равно попадут в результат с пустыми значениями номенклатуры. Если такие записи вам не нужны — используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ.Контрагент.СГРУППИРОВАТЬ ПО в финальном запросе и использовать агрегатные функции, такие как СУММА(Количество).Таким образом, мы разобрали, что получение данных из последних документов требует внимательного отношения к структуре запроса. Использование временных таблиц и правильная обработка дублей по времени позволяют создать стабильное и быстрое решение для любой конфигурации на платформе 1С.