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

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке отчетов или динамических списков часто возникает задача вывести документы разных типов в одну таблицу так, чтобы они располагались не группами по типам (сначала все Заказы, потом все Реализации), а в хронологическом или логическом порядке. Например, чтобы за Заказом покупателя №103 сразу шел Заказ на производство №103 и Комплектация №103. Рассмотрим, как правильно спроектировать такой запрос, используя механизмы платформы 1С.

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

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

Шаг 1: Подготовка данных во временных таблицах

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

Сначала выберем основные заказы во временную таблицу ВТЗаказы:


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

Обратите внимание, что мы сохраняем и Ссылка, и Номер. Это критически важно, так как именно по полю Номер мы будем выполнять финальную сортировку, чтобы «схлопнуть» разные типы документов в одну группу.

Шаг 2: Получение связанных документов

Теперь рассмотрим, как получить подчиненные или связанные документы. Допустим, нам нужны Заказы на производство, связанные с нашими заказами покупателей через табличную часть, и Отчеты производства за смену. Проанализируем важный нюанс: у отчетов производства может быть свой номер, не совпадающий с номером заказа. Чтобы они отобразились в списке рядом с заказом, мы должны в поле Номер принудительно подставить номер родительского документа.


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

Шаг 3: Объединение и финальная сортировка

Теперь соберем все данные вместе. Для того чтобы сортировка работала корректно, мы должны обеспечить одинаковый набор полей во всех частях объединения. Основной секрет заключается в том, чтобы обернуть ОБЪЕДИНИТЬ ВСЕ во вложенный запрос (в нашем примере он назван взДокументы) и применить УПОРЯДОЧИТЬ ПО в самом конце.

Рассмотрим итоговую структуру запроса:


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

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

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

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

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

УПОРЯДОЧИТЬ ПО
    НомерСортировки

Важные технические замечания по сортировке

Проанализируем несколько тонкостей, которые могут повлиять на результат:

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

Оптимизация: Соединения вместо условий В (...)

Выясним причину, по которой опытные разработчики часто заменяют конструкцию ГДЕ Ссылка В (ВЫБРАТЬ...) на ВНУТРЕННЕЕ СОЕДИНЕНИЕ. При работе с большими объемами данных в таблицах Документ.ЗаказНаПроизводство.Продукция поиск через соединение с индексированной временной таблицей работает быстрее. Рассмотрим, как изменить один из блоков:


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

Такой подход делает запрос более "профессиональным" с точки зрения производительности SQL-сервера. Мы проанализировали основные способы группировки документов в цепочки внутри запроса и выяснили, что ключ к успеху — это унификация полей (особенно поля Номер) и использование вложенных запросов для итогового упорядочивания.

← На главную