При разработке регламентированных отчетов в 1С:Предприятии 8.3 мы часто сталкиваемся с необходимостью точного упорядочивания данных, особенно при использовании группировок. Однако иногда возникают ситуации, когда директива УПОРЯДОЧИТЬ ПО, казалось бы, работает некорректно, а данные при обходе по группировкам выдаются в хаотичном порядке. Давайте разберем эту проблему и найдем эффективное решение.
Представьте, что перед нами стоит задача построить регламентированный отчет, в котором данные должны быть представлены в строгой иерархии: сначала по полю «МестоОсуществленияДеятельности», затем по «ВидИзмерений», и далее по «ГруппаСредствИзмерений». При этом «МестаОсуществленияДеятельности» должны сортироваться по собственному полю «Порядок», а «ВидИзмерений» и «ГруппаСредствИзмерений» — по их коду.
Мы составляем запрос, используя предложения УПОРЯДОЧИТЬ ПО и ИТОГИ ПО, что является стандартным подходом для получения итоговых данных с заданной структурой. Изначальный запрос мог бы выглядеть примерно так:
ВЫБРАТЬ
ВтОснащенность.ВидИзмерений КАК ВидИзмерений,
ВтОснащенность.КодВидаИзмерений КАК КодВидаИзмерений,
МестаОсуществленияДеятельностиКонтактнаяИнформация.Представление КАК МестоОсуществленияДеятельности,
МестаОсуществленияДеятельностиКонтактнаяИнформация.Ссылка.Порядок КАК МестоОсуществленияДеятельностиПорядок,
ВтОснащенность.ГруппаСредствИзмерений КАК ГруппаСредствИзмерений,
ВтОснащенность.ГруппаСредствИзмеренийКод КАК ГруппаСредствИзмеренийКод,
ВтОснащенность.ПорядокПоТипуОборудования КАК ПорядокПоТитуОборудования
ИЗ
// ... ваш источник данных, например, временная таблица ВтОснащенность ...
// ... и объединения, например, с МестаОсуществленияДеятельностиКонтактнаяИнформация ...
УПОРЯДОЧИТЬ ПО
МестоОсуществленияДеятельностиПорядок,
КодВидаИзмерений,
ГруппаСредствИзмеренийКод,
ПорядокПоТипуОборудования
ИТОГИ ПО
МестоОсуществленияДеятельности,
ВидИзмерений,
ГруппаСредствИзмерений
Однако при обходе результата запроса по группировкам мы обнаруживаем, что указанный в УПОРЯДОЧИТЬ ПО порядок сортировки игнорируется. Итоговые записи выдаются в конкретном, но совершенно непредсказуемом порядке. Часто этот порядок оказывается похожим на тот, в котором ссылки вводились в базу данных, что указывает на сортировку по внутреннему представлению ссылки (уникальному идентификатору).
Эта ситуация может сбить с толку, поскольку, согласно документации, УПОРЯДОЧИТЬ ПО должно определять порядок следования записей. Проблема усугубляется отсутствием явных разъяснений в документации 1С относительно взаимодействия УПОРЯДОЧИТЬ ПО и ИТОГИ ПО, особенно при обходе по группировкам.
Для того чтобы понять, почему возникает такая ситуация, рассмотрим, как именно работают предложения ИТОГИ ПО и УПОРЯДОЧИТЬ ПО в запросах 1С:Предприятия:
Неявное добавление группировок: Ключевое предложение ИТОГИ ПО не только подводит итоги, но и неявно добавляет группировки по тем полям, по которым эти итоги подводятся. Это означает, что при обходе результата запроса по группировкам, именно эти поля (указанные в ИТОГИ ПО) будут определять уровни иерархии обхода. Если мы используем конструкцию ИТОГИ ПО Общие, то явные группировки не создаются, но в случае с конкретными полями группировки появляются.
Приоритет упорядочивания:
ИТОГИ ПО (и отсутствует УПОРЯДОЧИТЬ ПО), то результат запроса будет упорядочен по полям, указанным в предложении ИТОГИ ПО, в том же порядке.УПОРЯДОЧИТЬ ПО, и ИТОГИ ПО, то каждый уровень итогов (т.е. каждая группировка) будет упорядочиваться отдельно. Это означает, что порядок строк внутри каждой группировки будет определяться УПОРЯДОЧИТЬ ПО, но сам порядок следования группировок будет определяться полями из ИТОГИ ПО.Проблема с псевдонимами: Обобщая наблюдаемое, мы можем сделать вывод, что парсер запросов 1С:Предприятия имеет особенность. При разборе предложения УПОРЯДОЧИТЬ ПО в сочетании с ИТОГИ ПО он может некорректно подставлять псевдонимы полей. То есть, если мы определяем поле с псевдонимом (например, МестаОсуществленияДеятельностиКонтактнаяИнформация.Ссылка.Порядок КАК МестоОсуществленияДеятельностиПорядок), а затем пытаемся упорядочить по этому псевдониму (МестоОсуществленияДеятельностиПорядок), система может "терять" связь между псевдонимом и исходным разыменованным полем при формировании внутренних структур для сортировки группировок.
Именно из-за этой особенности, когда система не может однозначно определить поле для сортировки по псевдониму в контексте группировок, она "молчаливо" игнорирует указанный порядок и прибегает к сортировке по умолчанию, которая для ссылочных типов чаще всего происходит по внутреннему уникальному идентификатору (UUID). Это и приводит к тому самому "хаотичному" порядку, который мы наблюдаем.
К счастью, решение этой проблемы оказывается довольно простым и элегантным. Оно заключается в том, чтобы использовать прямые ссылки на поля через точечную нотацию в предложении УПОРЯДОЧИТЬ ПО, избегая использования псевдонимов для тех полей, по которым мы хотим упорядочить.
Прямое указание полей: Вместо того чтобы полагаться на псевдонимы, которые мы присвоили полям в секции ВЫБРАТЬ, нам необходимо прямо указать полный путь к реквизиту, по которому требуется выполнить сортировку. Это гарантирует, что система запросов 1С однозначно идентифицирует и использует нужное поле для упорядочивания, даже в сочетании с группировками.
Пример рабочего запроса: Давайте посмотрим, как будет выглядеть исправленный запрос, который корректно выполняет упорядочивание:
ВЫБРАТЬ
ВтОснащенность.ВидИзмерений КАК ВидИзмерений,
// ... другие поля ...
МестаОсуществленияДеятельностиКонтактнаяИнформация.Представление КАК МестоОсуществленияДеятельности,
// ... другие поля ...
ИЗ
// ... ваш источник данных ...
// ... и объединения ...
УПОРЯДОЧИТЬ ПО
МестаОсуществленияДеятельностиКонтактнаяИнформация.Ссылка.Порядок,
ВидИзмерений.Код,
ГруппаСредствИзмерений.Код,
ПорядокПоТипуОборудования
ИТОГИ МАКСИМУМ(МестоОсуществленияДеятельности)
ПО
МестаОсуществленияДеятельностиКонтактнаяИнформация.Ссылка,
ВидИзмерений,
ГруппаСредствИзмерений
Пояснения к рабочему запросу:
МестаОсуществленияДеятельностиКонтактнаяИнформация.Ссылка.Порядок: Здесь мы видим ключевое изменение. Вместо псевдонима МестоОсуществленияДеятельностиПорядок мы напрямую обращаемся к реквизиту Порядок через ссылку МестаОсуществленияДеятельностиКонтактнаяИнформация.Ссылка. Это обеспечивает правильную идентификацию поля для сортировки.ВидИзмерений.Код, ГруппаСредствИзмерений.Код: Для ссылочных типов, которые мы хотим сортировать по их коду (а не по внутреннему UUID), мы явно указываем реквизит .Код. Это общепринятая практика, обеспечивающая предсказуемый и логичный для пользователя порядок.ИТОГИ ПО: В этом примере мы также немного модифицировали предложение ИТОГИ ПО, чтобы оно использовало прямые ссылки (МестаОсуществленияДеятельностиКонтактнаяИнформация.Ссылка) или поля, по которым идет основная сортировка, гарантируя согласованность уровней группировки и сортировки. Функция агрегации МАКСИМУМ(МестоОсуществленияДеятельности) приведена как пример, она может быть любой другой, подходящей для ваших итогов.Применение этого подхода позволяет системе запросов корректно обрабатывать условия упорядочивания, и при обходе по группировкам вы получите данные в том строгом порядке, который был задан в УПОРЯДОЧИТЬ ПО. Для наглядного вывода и анализа иерархических выборок подойдёт обработка для вывода результата запроса в дерево значений.
Разбирая эту ситуацию, мы также можем подчеркнуть несколько важных аспектов, касающихся упорядочивания ссылочных полей в запросах 1С:
Сортировка по внутреннему представлению по умолчанию: Если мы пытаемся сортировать по ссылочному полю напрямую, без указания его реквизитов (например, просто МестоОсуществленияДеятельности), то по умолчанию система будет сортировать по внутреннему представлению ссылки. Это уникальный идентификатор (UUID), который никак не связан с логическим порядком, ожидаемым пользователем (например, по алфавиту или по коду). Именно это "молчаливое" поведение и приводит к "хаотичному" порядку, который часто наблюдают разработчики.
Явное указание реквизитов для предсказуемости: Чтобы обеспечить ожидаемое пользователем упорядочивание ссылочных полей (по коду, наименованию, дате или другому реквизиту), всегда необходимо явно указывать этот реквизит в предложении УПОРЯДОЧИТЬ ПО (например, ВидИзмерений.Код или ГруппаСредствИзмерений.Наименование). Это гарантирует, что сортировка будет выполняться по значению примитивного типа (число, строка, дата), что является предсказуемым.
В контексте упорядочивания запросов в 1С мы можем также встретить рекомендацию использовать ключевое слово АВТОУПОРЯДОЧИВАНИЕ. Однако важно понимать, что этот механизм имеет свои особенности и не всегда является подходящим решением, особенно в нашем случае:
Не работает для нетиповых реквизитов: АВТОУПОРЯДОЧИВАНИЕ предназначено для автоматического выбора полей сортировки для стандартных ссылочных типов (например, для документов — по дате и номеру, для справочников — по коду или наименованию). Оно не учитывает произвольные или специфические реквизиты, такие как наше поле Порядок, которое не является стандартным реквизитом для сортировки.
Изменчивость порядка: Порядок, определяемый АВТОУПОРЯДОЧИВАНИЕ, может молчаливо измениться при изменении настроек справочника или типа документа. В случаях, когда порядок данных регламентируется законодательством или должен быть строго фиксированным (как в примере автора), такое поведение крайне нежелательно и может привести к несоответствиям.
Влияние на производительность: Использование АВТОУПОРЯДОЧИВАНИЕ может значительно увеличить время выполнения запроса, поскольку система вынуждена производить дополнительные операции по определению и применению полей для сортировки.
Потеря контроля: Разработчик теряет контроль над тем, какие именно поля будут использованы для упорядочивания, что противоречит принципу явного и предсказуемого поведения системы. Его применение оправдано только в тех случаях, когда порядок записей не критичен, но должен быть одинаковым независимо от используемой СУБД (например, при выгрузке данных для отладки).
Таким образом, для точного и контролируемого упорядочивания, особенно с нестандартными реквизитами и строгими требованиями к отчетности, рекомендуется избегать АВТОУПОРЯДОЧИВАНИЕ и явно указывать все поля сортировки.
Помимо рассмотренного решения, давайте обобщим некоторые важные рекомендации, которые помогут нам при работе с упорядочиванием запросов в 1С:
Использование УПОРЯДОЧИТЬ ПО обязательно: Если алгоритм обработки результатов запроса зависит от порядка записей или если результат представляется пользователю, то использование УПОРЯДОЧИТЬ ПО является критически важным. В противном случае порядок записей может быть непредсказуемым и может меняться при смене СУБД, версии СУБД или её параметров, что делает отчеты или обработки ненадежными.
Производительность: Дополнительное упорядочивание данных всегда создает избыточную нагрузку на СУБД. Поэтому следует использовать УПОРЯДОЧИТЬ ПО только при необходимости. Если порядок следования строк не имеет значения для логики работы или представления данных, то лучше его не указывать, чтобы не тратить ресурсы системы.
Обработка NULL: При сортировке по полю, которое может содержать значение NULL, необходимо учитывать, что в разных СУБД порядок сортировки для таких значений может отличаться. Для обеспечения предсказуемого и единообразного порядка рекомендуется использовать функции для обработки NULL, например, ЕСТЬNULL(). Например, УПОРЯДОЧИТЬ ПО ЕСТЬNULL(МоеПоле, ЗначениеПоУмолчанию).
Таким образом, внимательное отношение к использованию псевдонимов, предпочтение прямых ссылок в УПОРЯДОЧИТЬ ПО, понимание взаимодействия с ИТОГИ ПО, а также осознанное применение общих рекомендаций по упорядочиванию, помогут нам создавать надежные, предсказуемые и производительные запросы в 1С:Предприятии. Для отладки и проверки сложных запросов с группировками можно использовать консоль запросов для 1С на управляемых формах.