Как упорядочить строки таблицы значений в 1С: метод Сортировать, деревья, формы и запросы
Содержание
Чтобы отсортировать таблицу значений в 1С 8.3, вызовите у неё метод Сортировать() и передайте строку с колонками: ТЗ.Сортировать("Сумма Убыв, Дата Возр"). Таблица переупорядочивается на месте, метод ничего не возвращает, и присваивать результат в переменную не нужно.
Частое заблуждение — что сортировку ускоряет индекс. Нет: ТЗ.Индексы.Добавить() ускоряет поиск строк, а порядок строк не меняет вообще. Ниже — все рабочие способы: от кнопки в пользовательском режиме до сортировки по вычисляемому ключу и через запрос.
Что нужно знать о таблице значений перед сортировкой
Таблица значений (ТаблицаЗначений) — универсальная коллекция в памяти: строки, колонки, у каждой колонки может быть описание типов. Она живёт только на сервере и в толстом клиенте. В тонком клиенте и веб-клиенте этого типа нет — на управляемой форме вы работаете с её «отражением», коллекцией данных формы.
Что влияет на результат сортировки:
- 🔤 Тип значений в колонке. Числа сравниваются как числа, строки — как строки, даты — хронологически.
- 🔗 Ссылки. Справочники и документы по умолчанию сравниваются не по наименованию, а по внутреннему представлению ссылки. Отсюда «случайный» порядок, если сортировать по
Номенклатура. - 🧩 Смешанные типы. Если в колонке без описания типов лежат и числа, и строки, значения разных типов группируются по типу, и порядок внутри получается неочевидным.
- 📌 Порядок строк хранится. После сортировки индекс строки (
ТЗ.Индекс(Строка)) меняется. Если вы запомнили номера строк до сортировки, после неё они указывают на другие строки.
Сортировка таблиц в пользовательском режиме, без кода
Программировать не обязательно, если таблица уже выведена на экран.
Табличная часть документа или таблица на форме
- Выделите любую ячейку в нужной колонке.
- Откройте меню
Ещёв командной панели таблицы. - Выберите
Сортировать по возрастаниюилиСортировать по убыванию.
Так можно упорядочить, например, товары в документе по наименованию перед печатью. Порядок строк сохранится в документе после записи.
В проведённом документе сортировка табличной части меняет номера строк. Если на номера строк ссылается другая табличная часть (например, серии или коды маркировки по номеру строки), сначала проверьте, как это устроено в вашей конфигурации.
Списки справочников и документов
В динамическом списке щёлкните по заголовку колонки — список упорядочится по ней, повторный щелчок меняет направление. Для сортировки по нескольким полям откройте настройки списка через меню Ещё и задайте порядок полей на вкладке сортировки.
Отчёты на СКД
В отчёте нажмите Настройки, переключитесь в расширенный режим и добавьте поля в раздел сортировки. Направление указывается у каждого поля отдельно. Настройку можно сохранить как вариант отчёта.
Метод Сортировать(): программная сортировка таблицы значений
Синтаксис:
ТаблицаЗначений.Сортировать(<Колонки>, <ОбъектСравнения>);
- Колонки — строка с именами колонок через запятую. После имени через пробел указывается направление:
Возр(по умолчанию) илиУбыв. Английские варианты —AscиDesc. - ОбъектСравнения — необязательный параметр, объект
СравнениеЗначений. Нужен, когда в колонках ссылки и сортировать их надо по представлению.
Пример 1: одна колонка
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Товар", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
Строка = ТЗ.Добавить(); Строка.Товар = "Бумага А4"; Строка.Сумма = 1200;
Строка = ТЗ.Добавить(); Строка.Товар = "Скрепки"; Строка.Сумма = 150;
Строка = ТЗ.Добавить(); Строка.Товар = "Тонер"; Строка.Сумма = 4300;
ТЗ.Сортировать("Сумма Убыв");
// Порядок: Тонер 4300, Бумага А4 1200, Скрепки 150
Пример 2: несколько колонок
ТЗ.Сортировать("Контрагент, Дата Убыв, Сумма Убыв");
Сначала строки группируются по контрагенту по возрастанию. Внутри контрагента — свежие даты сверху. При равной дате выше идёт большая сумма.
Пример 3: ссылки по наименованию
ТЗ.Сортировать("Номенклатура", Новый СравнениеЗначений);
С объектом СравнениеЗначений ссылки упорядочиваются по представлению, то есть по тому тексту, который пользователь видит в ячейке. Без него порядок формально стабилен, но для человека выглядит хаотично.
💡 Если нужен алфавитный порядок только по одной ссылочной колонке, а остальные — числа и даты, СравнениеЗначений всё равно можно передавать: на примитивные типы он не влияет, просто работает чуть медленнее.
Сортировка на управляемой форме
Если таблица — реквизит формы, на клиенте у вас коллекция данных формы. У неё тоже есть метод Сортировать() с той же строкой колонок:
&НаКлиенте
Процедура УпорядочитьПоСумме(Команда)
Объект.Товары.Сортировать("Сумма Убыв");
КонецПроцедуры
Если нужен СравнениеЗначений или сложная логика, преобразуйте реквизит в таблицу значений на сервере:
&НаСервере
Процедура УпорядочитьНаСервере()
ТЗ = РеквизитФормыВЗначение("ТаблицаДанных");
ТЗ.Сортировать("Номенклатура, Сумма Убыв", Новый СравнениеЗначений);
ЗначениеВРеквизитФормы(ТЗ, "ТаблицаДанных");
КонецПроцедуры
Табличная часть объекта
Надёжный путь для табличной части в коде объекта — выгрузить, отсортировать, загрузить обратно:
ТЗ = ДокументОбъект.Товары.Выгрузить();
ТЗ.Сортировать("Номенклатура", Новый СравнениеЗначений);
ДокументОбъект.Товары.Загрузить(ТЗ);
Ручной порядок: переместить одну строку
Иногда нужна не сортировка, а перестановка конкретной строки: поднять итоговую позицию наверх или опустить служебную вниз. Для этого есть метод Сдвинуть(), он принимает строку и смещение (отрицательное — вверх):
Строка = ТЗ.Найти("Итого", "Товар");
Если Строка <> Неопределено Тогда
ТЗ.Сдвинуть(Строка, -ТЗ.Индекс(Строка)); // в самое начало
КонецЕсли;
Так удобно доводить порядок после Сортировать(), если одна-две строки должны стоять вне общего правила. Положительное смещение двигает строку вниз: ТЗ.Сдвинуть(Строка, 1) опускает её на одну позицию. Выход за границы таблицы вызовет ошибку, поэтому смещение считайте от текущего индекса.
Соседняя коллекция: список значений
Если данные — одна колонка значений, таблица не нужна. У СписокЗначений свои методы: СортироватьПоЗначению() и СортироватьПоПредставлению(), направление задаётся системным перечислением:
Список.СортироватьПоЗначению(НаправлениеСортировки.Убыв);
Список.СортироватьПоПредставлению(НаправлениеСортировки.Возр);
Сортировка по представлению полезна, когда в списке лежат ссылки, а показывать их надо по алфавиту.
Индексы таблицы значений: что они дают и чего не делают
Индекс в таблице значений создают так:
ТЗ.Индексы.Добавить("Контрагент, Договор");
Он ускоряет Найти() и НайтиСтроки() по этим колонкам на больших таблицах. На порядок строк индекс не влияет: после его создания строки стоят там же, где стояли.
Когда индекс полезен в связке с сортировкой:
| Задача | Что делать |
|---|---|
| Вывести строки в нужном порядке | Сортировать() |
| Много раз искать строки по ключу | Индексы.Добавить() + НайтиСтроки() |
| Найти и упорядочить найденное | НайтиСтроки() возвращает массив, его в таблицу не сортируют — сначала Сортировать() всю таблицу, потом ищите |
💡 Удобный приём: отсортируйте таблицу, затем вызовите НайтиСтроки(). Строки в возвращаемом массиве идут в том порядке, в каком стоят в таблице, — то есть уже упорядоченными.
Как отсортировать дерево значений с иерархией
У дерева значений метод Сортировать() есть у коллекции строк — у корневой и у каждого узла:
Дерево.Строки.Сортировать("Наименование", Истина);
Второй параметр Истина означает: сортировать и вложенные уровни, рекурсивно. При Ложь (по умолчанию) упорядочиваются только строки текущего уровня, а подчинённые остаются как были. Третьим параметром можно передать СравнениеЗначений.
Отсортировать только одну ветку:
Ветка = Дерево.Строки[0];
Ветка.Строки.Сортировать("Сумма Убыв", Истина);
Типичная задача — «папки сверху, элементы ниже, внутри по алфавиту». Решается через служебную колонку:
Дерево.Колонки.Добавить("ЭтоГруппаЧисло", Новый ОписаниеТипов("Число"));
// при заполнении: Строка.ЭтоГруппаЧисло = ?(Строка.ЭтоГруппа, 0, 1);
Дерево.Строки.Сортировать("ЭтоГруппаЧисло, Наименование", Истина);
Булево тоже сортируется (Ложь раньше Истина), но через число порядок задаётся явно и читается проще.
Сортировка по вычисляемым полям и нестандартным критериям
Сортировать() принимает только имена существующих колонок. Выражения вроде "Количество * Цена" не работают. Решение одно — временная колонка с ключом.
По вычисляемому значению
ТЗ.Колонки.Добавить("Ключ", Новый ОписаниеТипов("Число"));
Для Каждого Строка Из ТЗ Цикл
Строка.Ключ = Строка.Количество * Строка.Цена;
КонецЦикла;
ТЗ.Сортировать("Ключ Убыв");
ТЗ.Колонки.Удалить("Ключ");
Колонку удаляют после сортировки — порядок строк при этом сохраняется.
По своему порядку значений
Например, статусы должны идти так: «Срочно», «В работе», «Ожидает», остальные — в конце.
Ранги = Новый Соответствие;
Ранги.Вставить("Срочно", 1);
Ранги.Вставить("В работе", 2);
Ранги.Вставить("Ожидает", 3);
ТЗ.Колонки.Добавить("Ранг", Новый ОписаниеТипов("Число"));
Для Каждого Строка Из ТЗ Цикл
Ранг = Ранги.Получить(Строка.Статус);
Строка.Ранг = ?(Ранг = Неопределено, 99, Ранг);
КонецЦикла;
ТЗ.Сортировать("Ранг, Дата");
ТЗ.Колонки.Удалить("Ранг");
По реквизиту ссылки
Нужно упорядочить по артикулу номенклатуры, а в таблице лежит только ссылка. Обращение Строка.Номенклатура.Артикул в цикле — это отдельное чтение из базы на каждую строку. Лучше одним запросом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура,
| Т.Количество КАК Количество
|ПОМЕСТИТЬ ВТ
|ИЗ
| &ТЗ КАК Т
|;
|ВЫБРАТЬ
| ВТ.Номенклатура КАК Номенклатура,
| ВТ.Количество КАК Количество
|ИЗ
| ВТ КАК ВТ
|УПОРЯДОЧИТЬ ПО
| ВТ.Номенклатура.Артикул,
| ВТ.Количество УБЫВ";
Запрос.УстановитьПараметр("ТЗ", ТЗ);
ТЗ = Запрос.Выполнить().Выгрузить();
Таблица, передаваемая в запрос, должна иметь колонки с описанием типов. Колонка, созданная без ОписаниеТипов, вызовет ошибку при выполнении запроса.
Сравнение способов
| Способ | Когда подходит | Ограничения |
|---|---|---|
Сортировать("Колонка") | Примитивные типы, готовые колонки | Только существующие колонки |
+ СравнениеЗначений | Ссылки по представлению | Медленнее на больших объёмах |
| Временная колонка | Формулы, свой порядок значений | Нужен цикл заполнения |
Запрос с УПОРЯДОЧИТЬ ПО | Реквизиты ссылок, сложные условия | Только сервер, типизированные колонки |
Сортировка больших таблиц: как не тормозить
На таблицах в десятки и сотни тысяч строк заметны мелочи.
- 🗄️ Сортируйте в источнике. Если таблица получена запросом, добавьте
УПОРЯДОЧИТЬ ПОв сам запрос. СУБД упорядочит данные до выгрузки, иСортировать()не понадобится. - 🔁 Один раз, а не в цикле. Ошибка, которую часто видно в обработках:
Сортировать()внутри цикла добавления строк. Добавьте все строки, затем отсортируйте один раз. - 🏷️ Не передавайте
СравнениеЗначенийбез нужды. Сравнение по представлению требует получить текст каждой ссылки. - ✂️ Нужны первые N строк — берите
ВЫБРАТЬ ПЕРВЫЕ N ... УПОРЯДОЧИТЬ ПОв запросе, а не сортируйте и обрезайте всю таблицу. - 🖥️ Работайте на сервере. Передача большой таблицы между клиентом и сервером ради сортировки обходится дороже самой сортировки.
- 🧮 Сократите колонки. Метод
Скопировать()с перечнем колонок даёт облегчённую таблицу, если для вывода нужна только часть полей.
Короткая = ТЗ.Скопировать(, "Контрагент, Сумма");
Короткая.Свернуть("Контрагент", "Сумма");
Короткая.Сортировать("Сумма Убыв");
Здесь таблица сначала сворачивается по контрагенту с суммированием, а потом сортируется уже небольшой итог — так строят «топ контрагентов».