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

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

При работе с запросами в системе 1С:Предприятие часто возникает необходимость формирования временных таблиц для промежуточных вычислений. Хотя оператор ПОМЕСТИТЬ позволяет создать такую таблицу, синтаксис языка запросов не предусматривает прямое указание УПОРЯДОЧИТЬ ПО непосредственно для самой временной таблицы. То есть, мы не можем просто так отсортировать данные при их помещении. Однако, существуют эффективные методы для решения задач, требующих определенного порядка или уникальности данных при работе с временными таблицами. Мы подробно разберем несколько подходов, включая решение конкретной проблемы: как получить уникальные значения одного поля, связанных с минимальными значениями другого поля, и отсортировать их.

1. Получение уникальных значений с минимальным полем и последующей сортировкой

Давайте рассмотрим конкретную задачу, которая возникла у пользователя: имеется справочник с реквизитами Р1 и Р2. Требуется получить уникальные значения Р2, но таким образом, чтобы для каждого уникального Р2 выбиралось минимальное соответствующее ему значение Р1, и конечный результат был упорядочен по этому Р1. Например, если у нас есть пары ("А", 1), ("В", 1), мы хотим получить ("А", 1).

Для решения этой задачи мы можем использовать комбинацию агрегатной функции МИНИМУМ() и оператора СГРУППИРОВАТЬ ПО. Этот подход позволяет нам для каждого уникального значения Р2 найти минимальное значение Р1, а затем упорядочить полученный результат.

Разберем шаги:

  1. Выборка полей и агрегация: Мы выбираем поле P2 и применяем функцию МИНИМУМ() к полю P1.
  2. Группировка: Результат группируется по полю P2, чтобы агрегатная функция МИНИМУМ(P1) применялась к каждой группе с одинаковым P2.
  3. Упорядочивание: После получения уникальных P2 с соответствующими минимальными P1, мы можем упорядочить конечный результат по P1.

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


ВЫБРАТЬ
    Таблица.P2 КАК P2,
    МИНИМУМ(Таблица.P1) КАК P1
ИЗ
    МойТаблиц КАК Таблица
СГРУППИРОВАТЬ ПО
    Таблица.P2
УПОРЯДОЧИТЬ ПО
    P1

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

2. Использование оператора "ПЕРВЫЕ N" для косвенной сортировки при помещении во временную таблицу

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

Разберем ситуацию подробнее:

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

Посмотрим на пример использования этого метода:


ВЫБРАТЬ ПЕРВЫЕ 100500
    МойСправочник.Р1 КАК Р1,
    МойСправочник.Р2 КАК Р2
ПОМЕСТИТЬ ВременнаяТаблицаСортированная
ИЗ
    Справочник.МойСправочник КАК МойСправочник
УПОРЯДОЧИТЬ ПО
    Р1, Р2

В данном случае, данные будут выбраны из справочника, отсортированы по Р1, затем по Р2, и уже в таком порядке помещены во временную таблицу ВременнаяТаблицаСортированная. Этот метод является полезным, когда вам действительно необходимо гарантировать порядок записей внутри временной таблицы для дальнейших шагов запроса.

Важное замечание: Мы должны использовать число, достаточно большое, чтобы гарантировать выборку всех необходимых записей. 100500 часто используется как "большое" число, но в реальных системах с очень большим объемом данных следует быть внимательными и, возможно, использовать более адекватное число или проверять количество записей.

3. Индексирование временных таблиц: повышение производительности, но не гарантия сортировки

Оператор ИНДЕКСИРОВАТЬ ПО, который мы можем использовать при создании временных таблиц, является мощным инструментом для оптимизации производительности запросов. Индексирование полей во временной таблице значительно ускоряет операции соединения (СОЕДИНЕНИЕ), фильтрации (ГДЕ) и группировки (СГРУППИРОВАТЬ ПО) по этим полям.

Рассмотрим, как это работает:

  1. Создание временной таблицы: Мы сначала помещаем данные во временную таблицу.
  2. Индексирование: Сразу после оператора ПОМЕСТИТЬ мы добавляем блок ИНДЕКСИРОВАТЬ ПО, перечисляя поля, по которым требуется создать индексы.

Посмотрим на пример синтаксиса:


|ВЫБРАТЬ
|    Остатки.АналитикаУчетаПоПартнерам КАК АналитикаУчетаПоПартнерам,
|    Остатки.ЗаказПоставщику КАК ЗаказПоставщику,
|    Остатки.Валюта КАК Валюта,
|    Остатки.Период КАК Период,
|    Остатки.ДатаПлатежа КАК ДатаПлатежа,
|    Остатки.НовыйКОплатеОстаток КАК КОплатеОстаток,
|    Остатки.КОплатеОстатокНаКонецПериода КАК КОплатеОстатокНаКонецПериода,
|    Остатки.ПросроченнаяЗадолженность КАК ПросроченнаяЗадолженность
|ПОМЕСТИТЬ ТаблицаОстатковПоставщиков
|ИЗ
|    НовыеОстаткиПоставщиков КАК Остатки
|ИНДЕКСИРОВАТЬ ПО
|    АналитикаУчетаПоПартнерам,
|    ЗаказПоставщику,
|    Валюта

Критически важное уточнение: Несмотря на то что в некоторых случаях (особенно в файловой базе или при небольшом объеме данных) после индексирования может показаться, что данные во временной таблице отсортированы по индексированным полям, это не является гарантированным поведением. Это скорее побочный эффект внутренней работы СУБД, который может отличаться в зависимости от используемой базы данных (файловая, PostgreSQL, SQL Server), ее версии и объема данных.

Мы должны понимать, что основное назначение индекса – это ускорение поиска и доступа к данным, а не их сортировка. Поэтому, если логика вашего запроса требует определенного порядка записей во временной таблице, не следует полагаться только на индексирование. Для гарантированной сортировки используйте методы, описанные выше (агрегатные функции или ПЕРВЫЕ N с УПОРЯДОЧИТЬ ПО), или применяйте УПОРЯДОЧИТЬ ПО к конечной выборке из временной таблицы.

4. Функция "АВТОНОМЕРЗАПИСИ" для нумерации и гибкой работы с порядком

В более новых версиях платформы 1С:Предприятие появилась очень полезная функция АВТОНОМЕРЗАПИСИ. Эта функция позволяет автоматически присвоить порядковый номер каждой записи в результирующей выборке запроса. Это открывает новые возможности для различных сценариев, включая сложную нумерацию, ранжирование и косвенную работу с порядком данных.

Разберем возможности функции АВТОНОМЕРЗАПИСИ:

  1. Присвоение порядкового номера: Функция возвращает уникальный последовательный номер для каждой строки в результирующей выборке.
  2. Использование в связке с сортировкой: Мы можем создать временную таблицу, отсортировать данные по нужным полям, а затем присвоить им порядковые номера с помощью АВТОНОМЕРЗАПИСИ. Эти номера можно использовать для связывания данных, поддержания порядка или реализации других алгоритмов.
  3. Гибкость: Функция позволяет нам работать с порядком данных более гибко, не привязываясь к физической сортировке временной таблицы.

Посмотрим на пример использования АВТОНОНОМЕРЗАПИСИ для связывания отсортированных данных:


ВЫБРАТЬ
    1 КАК ДеньП, 10 КАК ДеньФ
ПОМЕСТИТЬ Данные
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 1, 11
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 15, 30
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 1, 30
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 1, 31
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 2, 10
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 2, 11
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 2, 30
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 2, 31
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 14, 10
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 14, 11
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 14, 30
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 14, 31
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 15, 10
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 15, 11
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 15, 31
;
////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Данные.ДеньП КАК ДеньП,
    АВТОНОМЕРЗАПИСИ КАК ПорядковыйНомер
ПОМЕСТИТЬ УпорядоченныеДниП
ИЗ
    Данные КАК Данные
ИНДЕКСИРОВАТЬ ПО
    ДеньП
;
////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
    Данные.ДеньФ КАК ДеньФ,
    АВТОНОМЕРЗАПИСИ КАК ПорядковыйНомер
ПОМЕСТИТЬ УпорядоченныеДниФ
ИЗ
    Данные КАК Данные
ИНДЕКСИРОВАТЬ ПО
    ДеньФ
;
////////////////////////////////////////////////////////////
ВЫБРАТЬ
    УпорядоченныеДниП.ДеньП КАК ДеньП,
    УпорядоченныеДниФ.ДеньФ КАК ДеньФ
ИЗ
    УпорядоченныеДниП КАК УпорядоченныеДниП
ПОЛНОЕ СОЕДИНЕНИЕ УпорядоченныеДниФ КАК УпорядоченныеДниФ
ПО
    УпорядоченныеДниП.ПорядковыйНомер = УпорядоченныеДниФ.ПорядковыйНомер

В этом примере мы сначала формируем исходные данные. Затем, в двух отдельных блоках, мы получаем уникальные значения ДеньП и ДеньФ, присваивая им порядковые номера с помощью АВТОНОМЕРЗАПИСИ. Обратите внимание, что мы также используем ИНДЕКСИРОВАТЬ ПО для повышения производительности этих временных таблиц. В заключительном шаге мы выполняем полное соединение по ПорядковыйНомер, чтобы связать отсортированные по разным критериям уникальные значения. Это позволяет нам косвенно управлять порядком и связями между данными.

Использование АВТОНОМЕРЗАПИСИ становится особенно актуальным в сценариях, где нам необходимо получить N-ую запись после сортировки, или реализовать более сложные алгоритмы ранжирования, которые невозможно выразить стандартными агрегатными функциями или простым УПОРЯДОЧИТЬ ПО.

Заключение

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

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

← На главную