При разработке отчетов и аналитических обработок в конфигурациях на платформе 1С:Предприятие (например, в «1С:Управление торговлей 11», «1С:ERP» или «1С:Комплексная автоматизация») часто возникает задача получить список партнеров с выводом самого последнего созданного документа по каждому из них (включая непроведенные и помеченные на удаление). При этом для части партнеров заказов может вовсе не быть в базе данных.
Разберем типичные ошибки при реализации такой выборки, выясним причины сбоев транслятора запросов СУБД и рассмотрим правильную архитектуру запроса с использованием временных таблиц.
Проанализируем распространенные подходы, которые приводят к ошибкам или некорректным результатам:
ВЫБРАТЬ ПЕРВЫЕ 1 во вложенном запросе левого соединения. Конструкция ВЫБРАТЬ ПЕРВЫЕ 1 ... УПОРЯДОЧИТЬ ПО Дата УБЫВ выбирает ровно одну запись из всей таблицы базы данных, а не по одной записи для каждого партнера. В итоге соединение сработает только для того единственного партнера, чей заказ оказался самым последним в системе.МАКСИМУМ(Ссылка) во вложенных запросах с DISTINCT или UNION. Внутренний механизм платформы 1С при трансляции запроса с агрегатными функциями по ссылкам на документы обращается к служебным полям даты и номера. Если структура полей в подзапросе не совпадает с ожиданиями платформы, возникает ошибка: «SDBL: Поле DATE_TIME отсутствует в разделе SELECT».Документ.ЗаказКлиента.Рассмотрим по шагам правильную структуру запроса. Чтобы получить последний документ по каждому партнеру из произвольного списка (например, отобранных партнеров без контрагентов), построим пакетный запрос:
МАКСИМУМ(Дата).Посмотрим на готовый текст запроса, решающий поставленную задачу:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Контрагенты.Партнер КАК Партнер
ПОМЕСТИТЬ ВТ_ПартнерыСКонтрагентами
ИЗ
Справочник.Контрагенты КАК Контрагенты
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Партнеры.Ссылка КАК Партнер,
Партнеры.Код КАК Код
ПОМЕСТИТЬ ВТ_ПроблемныеПартнеры
ИЗ
Справочник.Партнеры КАК Партнеры
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПартнерыСКонтрагентами КАК ВТ_ПартнерыСКонтрагентами
ПО (Партнеры.Ссылка = ВТ_ПартнерыСКонтрагентами.Партнер)
ГДЕ
ВТ_ПартнерыСКонтрагентами.Партнер ЕСТЬ NULL
ИНДЕКСИРОВАТЬ ПО
Партнер
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ПроблемныеПартнеры.Партнер КАК Партнер,
МАКСИМУМ(ЗаказКлиента.Дата) КАК МаксДата
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
ВТ_ПроблемныеПартнеры КАК ВТ_ПроблемныеПартнеры
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК ЗаказКлиента
ПО (ВТ_ПроблемныеПартнеры.Партнер = ЗаказКлиента.Партнер)
СГРУППИРОВАТЬ ПО
ВТ_ПроблемныеПартнеры.Партнер
ИНДЕКСИРОВАТЬ ПО
Партнер,
МаксДата
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ПроблемныеПартнеры.Партнер КАК Партнер,
ВТ_ПроблемныеПартнеры.Код КАК Код,
МАКСИМУМ(ЗаказКлиента.Ссылка) КАК ПоследнийЗаказ
ИЗ
ВТ_ПроблемныеПартнеры КАК ВТ_ПроблемныеПартнеры
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_МаксимальныеДаты КАК ВТ_МаксимальныеДаты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента КАК ЗаказКлиента
ПО (ВТ_МаксимальныеДаты.Партнер = ЗаказКлиента.Партнер)
И (ВТ_МаксимальныеДаты.МаксДата = ЗаказКлиента.Дата)
ПО (ВТ_ПроблемныеПартнеры.Партнер = ВТ_МаксимальныеДаты.Партнер)
СГРУППИРОВАТЬ ПО
ВТ_ПроблемныеПартнеры.Партнер,
ВТ_ПроблемныеПартнеры.Код
Разберем важные технические особенности представленного решения:
МАКСИМУМ(ЗаказКлиента.Ссылка) в финальной выборке гарантирует, что в отчет попадет строго одна строка на каждого партнера.ВТ_МаксимальныеДаты соединение с таблицей Документ.ЗаказКлиента происходит сразу с фильтрацией по ВТ_ПроблемныеПартнеры. Это предотвращает полное сканирование (Table Scan) многомиллионной таблицы заказов по всей базе данных.ИНДЕКСИРОВАТЬ ПО ускоряет последующие операции соединения, особенно при обработке больших списков элементов.Рассмотрим другие варианты решения задачи в зависимости от условий:
ВЫБРАТЬ ПЕРВЫЕ 1
ЗаказКлиента.Ссылка КАК Заказ,
ЗаказКлиента.Дата КАК Дата
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
ЗаказКлиента.Партнер = &Партнер
УПОРЯДОЧИТЬ ПО
ЗаказКлиента.Дата УБЫВ
Партнер. В подчиненном наборе заказов можно настроить отбор по максимальной дате или ограничение количества записей, что избавит от необходимости писать сложные пакетные соединения вручную.