Как поднять определенную строку наверх в результате запроса 1С?

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

При разработке алгоритмов заполнения документов, списания запасов или распределения затрат в 1С часто возникает задача приоритетной обработки определенных данных. Например, нам необходимо, чтобы при получении остатков по регистру конкретная номенклатура (или статья затрат) всегда оказывалась на первой строчке в результирующей таблице запроса, чтобы алгоритм списания обработал ее в первую очередь. В этой статье мы подробно разберем несколько способов решения этой задачи, проанализируем частые ошибки разработчиков и выясним, как эти механизмы работают "под капотом" СУБД.

Способ 1. Сортировка по булеву выражению (Быстрый способ)

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


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Код КАК Код,
    Номенклатура.Ссылка = &ПриоритетнаяНоменклатура КАК ЭтоПриоритет
ИЗ
    Справочник.Номенклатура КАК Номенклатура
УПОРЯДОЧИТЬ ПО
    ЭтоПриоритет УБЫВ

Важное предупреждение: обратите внимание на направление сортировки! Распространенная ошибка начинающих разработчиков — использовать сортировку по возрастанию (ВОЗР). В СУБД логическое значение Ложь эквивалентно числу 0, а значение Истина — числу 1. Если вы укажете направление ВОЗР, то сначала пойдут все строки со значением Ложь (все остальные элементы), а нужная строка со значением Истина окажется в самом низу выборки. Чтобы нужная строка гарантированно поднялась наверх, сортировать булево поле нужно строго по убыванию (УБЫВ).

Способ 2. Использование конструкции ВЫБОР КОГДА (Рекомендуемый и надежный способ)

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

  1. В списке выбора запроса создаем новое вычисляемое поле.
  2. Внутри конструкции ВЫБОР присваиваем приоритетному элементу числовой индекс 0, а всем остальным элементам — индекс 1.
  3. В секции УПОРЯДОЧИТЬ ПО указываем сортировку по нашему вычисляемому полю по возрастанию (ВОЗР).

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


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Код КАК Код,
    ВЫБОР
        КОГДА Номенклатура.Ссылка = &ПриоритетнаяНоменклатура ТОГДА 0
        ИНАЧЕ 1
    КОНЕЦ КАК ПорядокСортировки
ИЗ
    Справочник.Номенклатура КАК Номенклатура
УПОРЯДОЧИТЬ ПО
    ПорядокСортировки ВОЗР,
    Код ВОЗР

В данном примере приоритетный элемент получит значение поля ПорядокСортировки равное 0 и за счет сортировки ВОЗР окажется самым первым. Все остальные элементы получат индекс 1 и будут отсортированы ниже, упорядочиваясь между собой уже по дополнительному полю (в данном случае — по коду номенклатуры).

Способ 3. Использование ОБЪЕДИНИТЬ ВСЕ и его скрытая опасность

Иногда разработчики предлагают использовать объединение двух разных запросов. В первом запросе выбирается только приоритетный элемент, а во втором запросе — все остальные элементы (с исключением приоритетного через оператор НЕ или <>). Пример такой схемы:


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

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

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

Внимание: данный способ без явной сортировки опасен! У разработчиков часто возникает ложное ощущение порядка: кажется, что СУБД всегда возвращает строки именно в той последовательности, в которой они объединены в тексте запроса. На файловой базе или на небольших таблицах это действительно может совпадать. Однако, согласно стандарту SQL, СУБД (будь то MS SQL, PostgreSQL или Oracle) не гарантирует порядок строк в результате, если в запросе отсутствует явная секция УПОРЯДОЧИТЬ ПО. Оптимизатор СУБД может построить параллельный план выполнения или прочитать данные из индексов так, что строки из второй части объединения вернутся раньше первой.

Если вы всё же решили использовать ОБЪЕДИНИТЬ ВСЕ, обязательно добавьте синтетическое поле порядка в каждую часть запроса и выполните сортировку в самом конце:


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

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

ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Код КАК Код,
    1 КАК Порядок
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка <> &ПриоритетнаяНоменклатура

УПОРЯДОЧИТЬ ПО
    Порядок ВОЗР

Этот вариант абсолютно надежен, но делает текст запроса избыточно сложным и длинным по сравнению с использованием конструкции ВЫБОР.

Анализ производительности и трансляция в SQL

Давайте выясним, как платформа 1С транслирует эти конструкции в SQL-запросы для СУБД и как это влияет на скорость работы системы. Выражение Ссылка = &ПриоритетнаяНоменклатура преобразуется платформой в стандартную SQL-конструкцию CASE WHEN ... THEN 1 ELSE 0 END (так как во многих СУБД нет отдельного логического типа данных в таблицах, используются типы BIT или TINYINT).

С точки зрения производительности нужно учитывать объем обрабатываемых данных:

← На главную