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

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

При работе с запросами в 1С программисты часто сталкиваются с задачей получения «последнего» документа для каждого объекта (например, последней заявки для каждого контрагента). Ситуация осложняется, когда необходимо добавить дополнительный фильтр, например, по Типу цен. Прямолинейный подход с использованием вложенных запросов и соединений часто приводит к некорректным результатам, дублированию строк или получению пустых значений (NULL). Разберем по шагам, как построить эффективный и правильный запрос.

Анализ проблемы исходного запроса

Рассмотрим ситуацию, описанную автором темы. В исходном варианте использовался вложенный запрос с функцией МАКСИМУМ(ДатаИсполнения) и последующее левое соединение со справочником контрагентов. Такое решение имеет несколько критических недостатков:

  1. Неэффективность: Оптимизатору СУБД сложно обрабатывать вложенные запросы с группировками внутри соединений. Это может привести к значительному замедлению работы при росте базы.
  2. Проблема NULL: Использование ЛЕВОЕ СОЕДИНЕНИЕ со справочником контрагентов выводит всех контрагентов, даже тех, по которым не было заявок. Это часто избыточно, если нам нужны только те, кто совершал покупки.
  3. Сложность отбора: Попытка наложить условие ГДЕ ТипЦен = &ТипЦен во внешнем запросе после соединения может «отрезать» нужные данные или выдать неверный результат из-за особенностей работы соединений.

Проанализируем лучший способ решения этой задачи — использование временных таблиц.

Решение через использование временных таблиц (пакетные запросы)

Для корректной работы и высокой производительности разделим задачу на этапы. Это позволит нам четко контролировать данные на каждом шаге.

Шаг 1. Получение максимальной даты по каждому контрагенту. На этом этапе мы создаем временную таблицу, в которой будут храниться только ссылки на контрагентов и даты их последних заявок. При этом мы сразу накладываем фильтр по ВидЦены, чтобы искать последнюю дату именно среди заявок с нужным типом цен.


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

Обратите внимание на использование инструкции ИНДЕКСИРОВАТЬ ПО. Создание индекса во временной таблице по полям связи — критически важный момент для производительности последующих соединений.

Шаг 2. Выбор конкретных документов. Теперь, когда у нас есть пары «Контрагент — Дата», нам нужно получить ссылки на сами документы. Рассмотрим случай, если в одну секунду может быть несколько документов. Чтобы избежать дублей, добавим в выборку МАКСИМУМ(Ссылка).


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

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


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

Важные нюансы и оптимизация

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

1. Поле «Тип цен» в табличной части: Если тип цен указан не в шапке документа, а в каждой строке (табличная часть Товары), то логика меняется. Нам нужно сначала отобрать документы, содержащие нужный тип цен, используя ВЫБРАТЬ РАЗЛИЧНЫЕ Ссылка, и только потом искать среди них последний по дате.

2. Использование Момента Времени: В 1С Дата документа не всегда гарантирует его уникальность в последовательности. Для более точного позиционирования рекомендуется использовать МоментВремени(). В запросах это реализуется через связку Дата и Ссылка.

3. Использование Регистров сведений: Если задача получения последней цены или последнего документа стоит остро и база данных очень большая, рассмотрите возможность использования Регистра сведений. Создайте периодический регистр, в который при проведении документа будет записываться актуальный ТипЦен по контрагенту. В этом случае получение данных сведется к быстрому обращению к виртуальной таблице СрезПоследних, что работает в десятки раз быстрее любого сложного запроса по документам.

Рекомендации по написанию чистого кода

  1. Всегда предпочитайте Временные таблицы вложенным запросам. Это делает код читаемым для ваших коллег и «понятным» для оптимизатора SQL.
  2. Используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ вместо ЛЕВОЕ СОЕДИНЕНИЕ, если вам не нужны записи с пустыми значениями из правой таблицы.
  3. Не забывайте про Индексирование временных таблиц по полям, которые участвуют в секции ПО при соединении.

Таким образом, мы выяснили причину некорректной работы исходного запроса и предложили структурированный подход. Переход на пакетные запросы с использованием ПОМЕСТИТЬ — это стандарт современной разработки на платформе 1С, обеспечивающий стабильность и скорость работы системы.

← На главную