Как получить только последнюю строку в запросе 1С при работе с иерархией

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

В разработке на платформе 1С:Предприятие часто возникает задача получения одной конкретной строки из результата запроса. Если речь идет о простом списке, задача решается тривиально с помощью конструкции ВЫБРАТЬ ПЕРВЫЕ 1 и обратной сортировки. Однако, когда в данных присутствует иерархия или сложная логика вложенности, стандартные методы могут давать непредсказуемый результат. Разберем детально, почему так происходит и какие существуют стратегии решения этой задачи.

Проблема иерархической сортировки

Рассмотрим ситуацию: у нас есть временная таблица, содержащая данные с иерархией (например, справочник подразделений или номенклатуры). Мы хотим получить строку, которая визуально находится в самом низу списка. Попытка применить УПОРЯДОЧИТЬ ПО ... ИЕРАРХИЯ УБЫВАНИЕ вместе с ВЫБРАТЬ ПЕРВЫЕ 1 часто приводит к тому, что наверх поднимается корень последней ветки, а не конечный элемент (лист) иерархии. Проанализируем причину: платформа сначала выстраивает дерево по родительским связям, а затем применяет сортировку внутри каждого уровня. Это не позволяет «одним движением» вытащить именно ту строку, которая идет последней в общем плоском представлении дерева.

Решение 1: Метод искусственного упорядочивания (UNION ALL)

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


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

    ОБЪЕДИНИТЬ ВСЕ

    ВЫБРАТЬ
        2,
        Таблица.Ссылка
    ИЗ
        ВТ_Данные КАК Таблица
    ГДЕ
        Таблица.Условие = &УсловиеПредпоследнейСтроки) КАК Т

УПОРЯДОЧИТЬ ПО
    Т.ПорядокСтроки

В данном случае мы принудительно назначаем каждой строке числовой вес ПорядокСтроки. В итоговом запросе нам остается только выбрать ПЕРВЫЕ 1, предварительно отсортировав результат по возрастанию или убыванию этого веса. Это гарантирует, что даже при сложной иерархии мы получим именно ту запись, которую считаем приоритетной.

Решение 2: Имитация ROW_NUMBER через соединение

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

  1. Создаем временную таблицу ВТ_Исходная с нашими данными.
  2. Соединяем таблицу саму с собой по условию, что значение ключа в первой таблице меньше или равно значению во второй.
  3. Группируем по полям первой таблицы и вычисляем количество записей.

Рассмотрим пример кода:


ВЫБРАТЬ
    Т1.Ссылка КАК Ссылка,
    КОЛИЧЕСТВО(Т2.Ссылка) КАК НомерСтроки
ПОМЕСТИТЬ ВТ_СНомерами
ИЗ
    ВТ_Данные КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
        ПО Т1.КлючСортировки >= Т2.КлючСортировки
СГРУППИРОВАТЬ ПО
    Т1.Ссылка;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Данные.Ссылка
ИЗ
    ВТ_СНомерами КАК Данные
ГДЕ
    Данные.НомерСтроки = (ВЫБРАТЬ МАКСИМУМ(НомерСтроки) ИЗ ВТ_СНомерами)

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

Решение 3: Определение «листьев» иерархии

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


ВЫБРАТЬ
    Т1.Ссылка
ИЗ
    ВТ_Данные КАК Т1
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
        ПО Т1.Ссылка = Т2.Родитель
ГДЕ
    Т2.Ссылка ЕСТЬ NULL

Используя ЛЕВОЕ СОЕДИНЕНИЕ, мы отсекаем все группы, у которых есть подчиненные элементы. В результате остаются только конечные узлы. Если среди них нужно выбрать самый последний, можно дополнительно применить УПОРЯДОЧИТЬ ПО и ВЫБРАТЬ ПЕРВЫЕ 1.

Решение 4: Использование Момента Времени

Если ваша «последняя строка» определяется хронологией, самым надежным способом будет использование объекта МоментВремени. Он объединяет в себе дату, время и уникальную ссылку документа, что позволяет однозначно упорядочить записи, созданные даже в одну и ту же секунду. В запросе это выглядит следующим образом:


ВЫБРАТЬ ПЕРВЫЕ 1
    ДокументТаблица.Ссылка
ИЗ
    Документ.РеализацияТоваровУслуг КАК ДокументТаблица
УПОРЯДОЧИТЬ ПО
    ДокументТаблица.МоментВремени УБЫВАНИЕ

Важно помнить, что поле МоментВремени доступно не для всех типов объектов, а в основном для документов. Для справочников или записей регистров стоит использовать комбинацию даты и внутреннего идентификатора (ссылки).

Подведение итогов

Мы рассмотрели несколько способов получения последней строки. Выбор метода зависит от ваших ограничений: Метод объединения (UNION ALL) хорош для малых объемов данных с фиксированной логикой. Имитация нумерации (ROW_NUMBER) универсальна, но требовательна к ресурсам при больших объемах. Анализ иерархии (поиск листьев) идеален для работы с деревьями. Сортировка по Моменту Времени — стандарт де-факто для хронологических выборок.

← На главную