Разработка и Конфигурация · 11 мин
Как упорядочить временную таблицу в 1С
Как упорядочить временную таблицу в 1С: УПОРЯДОЧИТЬ ПО в запросе, сортировка таблицы значений методом Сортировать, типичные ошибки и примеры кода.
Временные таблицы в запросах 1С по умолчанию не имеют гарантированного порядка строк. Даже если на практике записи выглядят отсортированными, платформа этого не обещает: порядок выборки из временной таблицы определяется планом запроса и может меняться от выполнения к выполнению. Поэтому единственный надёжный способ получить упорядоченный результат — явно указать сортировку при обращении к временной таблице.
Существует два принципиально разных сценария. Первый — упорядочить данные прямо в запросе с помощью конструкции УПОРЯДОЧИТЬ ПО при выборке из временной таблицы. Второй — выгрузить результат в таблицу значений и отсортировать её встроенным методом Сортировать() уже на языке 1С. Выбор зависит от того, где данные будут использоваться дальше.
Важно понимать ограничение: предложение УПОРЯДОЧИТЬ ПО нельзя применять в запросе, который сам помещает данные во временную таблицу (с конструкцией ПОМЕСТИТЬ). Платформа просто не сохранит порядок при материализации таблицы. Сортировка имеет смысл только в финальном запросе пакета, результат которого читается выборкой или выгружается.
Как устроены временные таблицы и почему порядок не гарантирован
Временная таблица в 1С — это материализованный промежуточный результат запроса, который живёт в рамках менеджера временных таблиц и доступен последующим запросам пакета. Физически она хранится на сервере СУБД (или в памяти для файлового варианта) как набор строк без какого-либо индекса по умолчанию.
При создании временной таблицы платформа не запоминает порядок, в котором строки были получены исходным запросом. Даже если исходная выборка читалась из упорядоченного источника, после помещения во временную таблицу порядок считается неопределённым. Это стандартное поведение реляционных СУБД: таблица — это множество строк, а не упорядоченная последовательность.
Практический вывод: любая логика, зависящая от порядка строк (нумерация, накопительные итоги, группировка в обходе выборки), должна опираться на явную сортировку в финальном запросе. Полагаться на «как обычно выходит» нельзя — после изменения запроса, обновления платформы или роста объёма данных порядок может измениться.
Упорядочивание при выборке из временной таблицы
Основной и рекомендуемый способ — добавить предложение УПОРЯДОЧИТЬ ПО в запрос, который читает временную таблицу. Сортировать можно по любым полям выборки, в том числе по полям, полученным через соединение с другими таблицами.
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Количество КАК Количество
|ИЗ
| ВТ_Товары КАК Товары
|
|УПОРЯДОЧИТЬ ПО
| Количество УБЫВ,
| Номенклатура";
Ключевые слова ВОЗР и УБЫВ задают направление сортировки; по умолчанию используется возрастание. Если полей несколько, они перечисляются через запятую — сначала сортировка по первому полю, внутри одинаковых значений — по второму и так далее.
Дополнительно доступна конструкция АВТОУПОРЯДОЧИВАНИЕ. Она сортирует результат по ссылкам и представлениям ссылочных полей, если явное упорядочивание не задано. Полагаться на неё стоит только в простых случаях: для прикладной логики явное УПОРЯДОЧИТЬ ПО читаемее и предсказуемее.
Почему нельзя сортировать внутри запроса с ПОМЕСТИТЬ
Частая ошибка начинающих разработчиков — попытка написать УПОРЯДОЧИТЬ ПО в том же запросе, где данные помещаются во временную таблицу. Синтаксически конструктор запросов такую комбинацию не предлагает, а если сформировать текст вручную, платформа либо выдаст ошибку, либо проигнорирует сортировку.
Причина в том, что временная таблица материализуется как неупорядоченный набор строк. Даже если бы сортировка выполнялась при заполнении, последующее чтение всё равно не обязано её соблюдать. Поэтому правильный приём — перенести упорядочивание в финальный запрос пакета.
Если порядок нужен не для вывода, а для последующей обработки внутри пакета запросов (например, соединение «с предыдущей строкой»), стандартной сортировки недостаточно. Такие задачи решаются через нумерацию строк на стороне СУБД или через выгрузку в таблицу значений с последующим обходом.
Сортировка после выгрузки в таблицу значений
Когда результат запроса выгружается методом Выгрузить(), получается таблица значений — полноценный объект в памяти с собственными средствами сортировки. Метод Сортировать() принимает строку со списком колонок и направлений.
ТЗ = Запрос.Выполнить().Выгрузить();
ТЗ.Сортировать("Количество Убыв, Номенклатура Возр");
Направления задаются словами Возр и Убыв через пробел после имени колонки; колонки перечисляются через запятую. Если направление не указать, применяется сортировка по возрастанию. Метод выполняется в памяти, поэтому для очень больших таблиц выгоднее сортировать на стороне СУБД в запросе — там работают оптимизатор и индексы.
Для дерева значений есть аналогичные механизмы: сортировка строк конкретного уровня выполняется через коллекцию строк (Строки.Сортировать(...)). Это удобно при выводе иерархических данных в табличное поле или отчёт.
Где сортировать
Подходит для больших выборок и когда результат сразу обходится выборкой. Сортировка выполняется на СУБД, память клиента/сервера приложений не расходуется на промежуточную таблицу.
Подходит, когда данные уже в таблице значений и нужны дальнейшие манипуляции в коде. Ограничение: вся таблица находится в памяти, при больших объёмах это дороже.
Подходит для простых списков ссылок без требований к точному порядку. Не заменяет явную сортировку в прикладной логике.
Индексация временных таблиц и её связь с сортировкой
Конструкция ИНДЕКСИРОВАТЬ ПО в запросе с ПОМЕСТИТЬ создаёт индекс временной таблицы. Важно не путать: индекс ускоряет поиск и соединения, но не гарантирует порядок выборки. Даже проиндексированная временная таблица при чтении без УПОРЯДОЧИТЬ ПО может вернуть строки в любом порядке.
Индексировать стоит те поля, по которым временная таблица соединяется с другими таблицами или по которым идёт отбор. Это заметно ускоряет пакет запросов на больших объёмах. Сортировку же по-прежнему задавайте явно в финальном запросе — индекс и упорядочивание решают разные задачи.
Пошаговый порядок действий
Типовая последовательность работы с временной таблицей, когда требуется упорядоченный результат, выглядит так: сначала формируется пакет запросов с помещением промежуточных данных, затем финальный запрос читает временную таблицу с явной сортировкой.
- 1Создайте менеджер временных таблиц и назначьте его всем запросам пакета
- 2Сформируйте временную таблицу запросом с ПОМЕСТИТЬ (без сортировки в нём)
- 3При необходимости добавьте ИНДЕКСИРОВАТЬ ПО по полям соединений
- 4Напишите финальный запрос: ВЫБРАТЬ ... ИЗ ВТ_Имя ... УПОРЯДОЧИТЬ ПО полям
- 5Выполните запрос и обойдите выборку или выгрузите результат
- 6Если данные уже в таблице значений — примените ТЗ.Сортировать() с нужными колонками
- 7После завершения работы уничтожьте временные таблицы или закройте менеджер
После завершения работы временные таблицы желательно уничтожать явно (запросом УНИЧТОЖИТЬ или закрытием менеджера), особенно если пакет выполняется в длительной операции. Это освобождает ресурсы СУБД и снижает риск конфликтов имён при повторном использовании менеджера.
Типичные ошибки и как их проверить
Отдельная группа проблем — сортировка полей составного типа или полей, содержащих NULL. Значения NULL при сортировке по возрастанию обычно идут первыми; если это нарушает логику отчёта, используйте ЕСТЬNULL для замены на осмысленное значение или фильтруйте такие строки заранее.
Как проверить результат
Строки идут строго по указанным полям и направлениям, повторный запуск даёт тот же порядок
Порядок меняется между выполнениями или не соответствует УПОРЯДОЧИТЬ ПО — значит, сортировка задана не в финальном запросе
Числа упорядочены по значению (2, 10, 100)
Порядок «1, 10, 2» — поле строковое, нужна сортировка по числовому представлению
Пустые значения обработаны через ЕСТЬNULL и стоят в ожидаемом месте
Строки с NULL попадают в начало и нарушают логику обхода
Для отладки удобно временно выгрузить результат в таблицу значений и просмотреть её в отладчике или вывести через консоль запросов. Проверяйте не только первый десяток строк — проблемы сортировки часто проявляются на границах групп и на больших объёмах.
Что важно запомнить
Временная таблица не хранит порядок строк: сортировку задавайте только в финальном запросе через УПОРЯДОЧИТЬ ПО. Для данных, уже выгруженных в память, используйте ТЗ.Сортировать(). Индексы ускоряют соединения, но не заменяют упорядочивание.
Частые вопросы
Можно ли отсортировать саму временную таблицу, чтобы она хранилась упорядоченной?
Нет. Временная таблица — неупорядоченный набор строк, и платформа не предоставляет способа зафиксировать порядок хранения. Упорядочивание применяется только при чтении: добавьте УПОРЯДОЧИТЬ ПО в каждый запрос, которому важен порядок строк.
Чем АВТОУПОРЯДОЧИВАНИЕ отличается от УПОРЯДОЧИТЬ ПО?
АВТОУПОРЯДОЧИВАНИЕ сортирует по представлениям ссылочных полей и ссылкам без явного указания полей. Это удобно для простых списков, но не подходит, когда нужен конкретный порядок по реквизитам, числам или нескольким полям — там требуется УПОРЯДОЧИТЬ ПО.
Как отсортировать по полю, которого нет в выборке?
В запросе 1С сортировать можно по полям источника, даже если они не входят в список выборки — достаточно указать поле через псевдоним таблицы в УПОРЯДОЧИТЬ ПО. В таблице значений методом Сортировать() такой возможности нет: колонка должна существовать в таблице.
Почему числа сортируются как «1, 10, 2, 25»?
Поле имеет строковый тип, и сортировка выполняется посимвольно. Решения: привести значение к числу в запросе, сортировать по исходному числовому полю или дополнить строки лидирующими нулями до фиксированной длины.
Что быстрее — сортировка в запросе или методом Сортировать()?
На больших объёмах сортировка в запросе обычно эффективнее: она выполняется на СУБД без передачи всех данных в память приложения. Метод Сортировать() оправдан, когда таблица значений уже нужна в коде для дальнейшей обработки.
Нужно ли уничтожать временные таблицы после использования?
Желательно, особенно в длительных операциях и при больших объёмах. Используйте запрос УНИЧТОЖИТЬ ИмяТаблицы или закройте менеджер временных таблиц — это освобождает ресурсы СУБД и предотвращает конфликты имён при повторном выполнении пакета.