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