Как отобрать заказы по дате последней связанной реализации в 1С

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

При разработке отчетов в системе 1С часто возникает задача, когда стандартных фильтров СКД или простых условий в блоке ГДЕ недостаточно. Типичный пример: нам нужно вывести Заказ клиента только в том случае, если его последняя отгрузка (документ Реализация товаров и услуг) попадает в выбранный пользователем интервал дат. Если хотя бы одна, самая поздняя реализация, выходит за рамки периода «в будущее», весь заказ должен быть исключен из отчета.

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

Метод 1: Использование временной таблицы с максимальной датой (рекомендуемый)

Проанализируем наиболее оптимальный и производительный способ. Вместо того чтобы пытаться наложить условия на основные данные, мы сначала подготовим вспомогательную таблицу, которая ответит на вопрос: «Когда была последняя отгрузка по каждому заказу?».

Разберем этот метод по шагам:

  1. Создаем временную таблицу, в которой выбираем все реализации, группируем их по полю ЗаказКлиента и вычисляем МАКСИМУМ(Дата).
  2. Во втором запросе выбираем данные из этой временной таблицы, накладывая условие на полученную максимальную дату.
  3. Соединяем результат с основными таблицами для получения детальной информации.

Пример реализации в коде запроса:


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

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

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

Метод 2: Сравнение общего количества документов и количества в периоде

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

Логика такова: 1. Считаем, сколько всего проведено реализаций по заказу (Таблица А). 2. Считаем, сколько проведено реализаций по заказу в заданном периоде (Таблица Б). 3. Если значения в А и Б равны, значит, за пределами периода отгрузок нет.

Посмотрим на пример кода, предложенный автором:


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

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

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВременнаяТаблица.Заказ КАК Заказ
ИЗ
    ВременнаяТаблица КАК ВременнаяТаблица
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВременнаяТаблица1 КАК ВременнаяТаблица1
        ПО ВременнаяТаблица.Заказ = ВременнаяТаблица1.Заказ
ГДЕ
    ВременнаяТаблица.КоличестоВсего <= ВременнаяТаблица1.КоличествоОтборПоДате

Хотя этот метод рабочий, он может быть менее производительным на больших объемах данных из-за использования КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) и нескольких соединений больших таблиц документов.

Метод 3: Использование конструкции ИМЕЮЩИЕ (HAVING)

Проанализируем ситуацию, когда нам нужно написать максимально компактный запрос. Если нам не требуется выводить каждую реализацию отдельной строкой, а достаточно списка заказов, можно воспользоваться блоком ИМЕЮЩИЕ.


ВЫБРАТЬ
    Реализация.ЗаказКлиента КАК Заказ
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО
    Реализация.ЗаказКлиента
ИМЕЮЩИЕ
    МАКСИМУМ(Реализация.Дата) >= &ДатаНачала 
    И МАКСИМУМ(Реализация.Дата) <= &ДатаКонца

Этот запрос вернет только те ЗаказКлиента, у которых самая поздняя реализация входит в интервал. Это самый быстрый способ фильтрации «в один проход» по таблице реализаций.

Особенности реализации в СКД (Система компоновки данных)

Если вы разрабатываете отчет на СКД, помните о следующих инструментах:

Рекомендации по оптимизации

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

  1. Использование регистров: Вместо таблиц документов лучше обращаться к виртуальным таблицам регистров накопления, таких как ВыручкаИПродажи.Обороты или ЗаказыКлиентов. Поиск момента времени последнего движения по регистру обычно происходит быстрее благодаря индексам.
  2. Индексация: Временные таблицы (как в Методе 1) желательно индексировать по полю Заказ, если далее планируется соединение с ними.
  3. Проверка на NULL: При использовании ЛЕВОЕ СОЕДИНЕНИЕ всегда учитывайте ситуацию, когда отгрузок по заказу может не быть вовсе. Если ваша бизнес-логика требует исключать заказы без отгрузок, используйте ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

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

← На главную