Как в запросе 1С определить, есть ли для текущего документа следующий?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← К списку

Часто при работе с документами в 1С возникает задача: для каждого документа в выборке понять, является ли он последним или за ним следует еще один. Давайте вместе разберемся, как это можно реализовать с помощью запроса, проанализируем разные подходы и выясним, какой из них лучше подходит для вашей ситуации.

Прежде чем перейти к решениям, давайте четко определим, что мы понимаем под "следующим документом". В данном контексте это не документ, созданный на основании текущего. Это документ того же вида, который идет за текущим при строгой сортировке, как правило, по дате и времени. Если даты совпадают, для уникальности сортировки можно использовать саму ссылку на документ. Наша цель — для каждой строки результата запроса добавить признак, который покажет, существует ли такая "следующая" запись.

Решение 1: Классический подход с использованием левого соединения

Этот метод является "классикой" для решения подобных задач и будет работать на большинстве версий платформы 1С. Основная идея заключается в том, чтобы соединить таблицу документов саму с собой по определенному условию. Проанализируем этот способ по шагам.

  1. Подготовка данных. Сначала мы помещаем нужные нам документы во временную таблицу. Это позволяет ограничить выборку и сделать дальнейшие операции более быстрыми.
  2. Соединение таблицы с самой собой. Мы используем ЛЕВОЕ СОЕДИНЕНИЕ временной таблицы с ее же копией. Ключевой момент здесь — это условие соединения. Мы соединяем каждую строку первой таблицы (условно "текущий" документ) со всеми строками из второй таблицы ("потенциально следующие" документы), которые удовлетворяют условию следования.
  3. Условие следования. Чтобы документ считался следующим, он должен быть "больше" текущего. Мы определяем это по дате: ВТ2.Дата > ВТ.Дата. Но что делать, если даты и время документов совпадают? Чтобы сортировка была однозначной, мы добавляем второе условие через ИЛИ: если даты равны, то следующим будет тот документ, у которого ссылка "больше": (ВТ2.Дата = ВТ.Дата И ВТ2.Ссылка > ВТ.Ссылка).
  4. Группировка и подсчет. После соединения для каждого "текущего" документа мы получим столько строк, сколько для него нашлось "следующих". Чтобы получить итоговый признак, мы группируем результат по полям текущего документа и с помощью агрегатной функции КОЛИЧЕСТВО() считаем, сколько "следующих" ссылок было найдено. Если количество больше нуля, значит следующий документ существует.

Посмотрим на пример такого запроса. Допустим, мы работаем с документами ЗаказКлиента.


ВЫБРАТЬ
    ЗаказКлиента.Ссылка,
    ЗаказКлиента.Дата
ПОМЕСТИТЬ ВТ_Документы
ИЗ
    Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
    ЗаказКлиента.Дата >= &НачалоПериода;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.Ссылка,
    ВТ.Дата,
    КОЛИЧЕСТВО(ВТ2.Ссылка) КАК ЕстьСледующий
ИЗ
    ВТ_Документы КАК ВТ
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Документы КАК ВТ2
        ПО (ВТ2.Дата > ВТ.Дата
                ИЛИ (ВТ2.Дата = ВТ.Дата И ВТ2.Ссылка > ВТ.Ссылка))
СГРУППИРОВАТЬ ПО
    ВТ.Ссылка,
    ВТ.Дата

В результате этого запроса мы получим поле ЕстьСледующий, в котором будет число — количество документов, следующих за текущим. Если это число больше 0, значит, следующий документ есть. Этот метод надежен, но на очень больших объемах данных может быть не самым производительным из-за сложного условия соединения.

Решение 2: Современный и производительный метод с оконными функциями

Начиная с платформы 1С:Предприятие 8.3.16, в языке запросов появилась мощная возможность — оконные функции. Они идеально подходят для нашей задачи и позволяют получить более простой и производительный запрос. Нам не потребуется соединять таблицу саму с собой.

Рассмотрим подробнее, как они работают. Оконные функции позволяют выполнять вычисления на наборе строк, которые как-то связаны с текущей строкой. Для нашей задачи идеально подходит функция LEAD().

Функция LEAD(Поле) позволяет "заглянуть вперед" и получить значение поля из следующей строки в отсортированном наборе данных. Если следующей строки нет (то есть текущая строка последняя), функция вернет NULL.

Давайте разберем по шагам, как использовать этот подход:

  1. Формируем основной запрос. Выбираем все необходимые поля из таблицы документов.
  2. Добавляем вычисляемое поле с функцией LEAD(). В разделе ВЫБРАТЬ мы добавляем новое поле. Внутри функции LEAD() указываем поле, которое хотим получить из следующей строки (например, Ссылка).
  3. Задаем порядок сортировки. Обязательной частью оконной функции является секция НАД (в оригинальном SQL это OVER), в которой мы указываем, как именно нужно упорядочить данные, чтобы определить, какая строка является "следующей". Мы используем УПОРЯДОЧИТЬ ПО Дата, Ссылка.
  4. Анализируем результат. В итоговой выборке у нас будет новое поле. Если в этом поле значение NULL, значит, текущий документ — последний в выборке. Если там есть какое-то значение (например, ссылка на следующий документ), значит, следующий документ существует.

Посмотрим на пример запроса с использованием оконной функции:


ВЫБРАТЬ
    ЗаказКлиента.Ссылка,
    ЗаказКлиента.Дата,
    LEAD(ЗаказКлиента.Ссылка) НАД (УПОРЯДОЧИТЬ ПО ЗаказКлиента.Дата, ЗаказКлиента.Ссылка) КАК СсылкаСледующегоДокумента
ИЗ
    Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
    ЗаказКлиента.Дата >= &НачалоПериода

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

Вывод: если вы работаете на современной версии платформы (8.3.16 и выше), использование оконных функций является предпочтительным, более элегантным и производительным решением. Если же требуется совместимость с более старыми версиями, классический метод с левым соединением остается надежным рабочим вариантом.

← К списку