Метод Сортировать у ТаблицыЗначений: колонки, направления, свой порядок и запрос
Содержание
Таблицу значений сортируют одной строкой: Таблица.Сортировать("Сумма Убыв");. В параметре перечисляют колонки через запятую, после имени колонки через пробел ставят направление — Возр или Убыв. Без направления платформа сортирует по возрастанию. Метод меняет саму таблицу и ничего не возвращает.
Типичная ситуация: разработчик собирает в коде остатки по складам, сворачивает их и выводит в печатную форму, а заказчик просит «сначала крупные суммы, внутри — по алфавиту». Это решается сортировкой по двум колонкам. Сложнее, когда нужен нестандартный порядок: статусы в своей последовательности, ссылки по наименованию, даты внутри групп. Всё это тоже делается штатными средствами 1С 8.3, без ручных пузырьков.
Метод Сортировать: синтаксис и первый пример
Метод есть у объекта ТаблицаЗначений. Синтаксис:
Таблица.Сортировать(<Колонки>, <ОбъектСравнения>);
| Параметр | Тип | Что задаёт |
|---|---|---|
| Колонки | Строка | Имена колонок через запятую, у каждой — направление Возр или Убыв |
| ОбъектСравнения | СравнениеЗначений | Необязательный. Сравнение ссылок по представлению вместо внутреннего идентификатора |
Простейший рабочий пример — таблица создаётся, заполняется и сортируется:
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Покупатель", Новый ОписаниеТипов("Строка"));
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
Строка = Таблица.Добавить(); Строка.Покупатель = "Ромашка"; Строка.Сумма = 1500;
Строка = Таблица.Добавить(); Строка.Покупатель = "Альфа"; Строка.Сумма = 92000;
Строка = Таблица.Добавить(); Строка.Покупатель = "Вектор"; Строка.Сумма = 4300;
Таблица.Сортировать("Сумма Убыв");
// Альфа 92000, Вектор 4300, Ромашка 1500
Что нужно помнить о методе:
- 🔁 сортировка выполняется «на месте»: строки переставляются в этой же таблице;
- 🚫 метод — процедура, значения не возвращает. Запись
Таблица = Таблица.Сортировать("Сумма")превратит таблицу вНеопределено; - 🔤 ключевые слова
ВозриУбывпишутся в любом регистре, есть англоязычныеAscиDesc; - 🖥
ТаблицаЗначенийживёт на сервере, в толстом клиенте и во внешнем соединении. В тонком клиенте этого объекта нет, поэтому код сортировки ставьте в процедуру&НаСервере.
Если нужна отсортированная копия, а исходный порядок должен сохраниться, сначала сделайте Копия = Таблица.Скопировать();, затем сортируйте копию.
Отсортировать только часть строк
Метод всегда упорядочивает всю таблицу. Если нужен отсортированный список только по одному складу, сначала отберите строки в новую таблицу, затем сортируйте её:
Отбор = Новый Структура("Склад", СкладОсновной);
Часть = Таблица.Скопировать(Отбор, "Номенклатура, Количество, Сумма");
Часть.Сортировать("Сумма Убыв");
Второй параметр Скопировать оставляет только нужные колонки. Исходная таблица при этом не меняется: ни состав строк, ни их порядок. Это удобно, когда одна выборка идёт в несколько разделов отчёта с разной сортировкой.
Сортировка таблицы значений по нескольким колонкам
Колонки перечисляют через запятую. Первая — главный ключ, вторая работает только внутри одинаковых значений первой, и так далее.
Таблица.Сортировать("Склад Возр, Сумма Убыв, Номенклатура");
Здесь строки сначала сгруппируются по складу. Внутри склада пойдут крупные суммы, а при равной сумме — номенклатура по возрастанию: направление не указано, значит Возр.
Пример на данных:
| Склад | Сумма | Номенклатура |
|---|---|---|
| Основной | 9 000 | Бумага А4 |
| Основной | 9 000 | Картридж |
| Основной | 2 500 | Ручки |
| Розница | 14 000 | Степлер |
| Розница | 700 | Скрепки |
Пробелы после запятой не мешают, лишние пробелы между именем и направлением тоже. Мешает другое: опечатка в имени колонки. Тогда метод выбросит исключение, что колонка не найдена. Поэтому строку с колонками удобно собирать из констант или проверять заранее:
Если Таблица.Колонки.Найти("Склад") = Неопределено Тогда
ВызватьИсключение "В таблице нет колонки Склад";
КонецЕсли;
Частый сценарий — Свернуть, затем Сортировать. Сначала сворачивайте: Таблица.Свернуть("Склад, Номенклатура", "Количество, Сумма");, и только потом упорядочивайте результат. После свёртки порядок строк не гарантирован.
Как типы данных влияют на порядок строк
Результат сортировки зависит от того, что лежит в колонке. Правила для основных типов:
| Тип значения | Порядок по возрастанию |
|---|---|
| Число | от меньшего к большему, отрицательные раньше нуля |
| Дата | от ранней к поздней, пустая дата '00010101' — первой |
| Булево | Ложь, затем Истина |
| Строка | по символам, слева направо |
| Ссылка | по внутреннему идентификатору, если не передан СравнениеЗначений |
Строки с цифрами
Строки сравниваются посимвольно. Поэтому «Склад 10» окажется раньше «Склад 2»: символ «1» меньше «2». То же со строковыми номерами документов без ведущих нулей.
Решение — отдельная числовая колонка или номер с ведущими нулями. Для числа из строки используйте Число() внутри Попытка, если в данных возможен мусор.
Ссылки: справочники и документы
Без второго параметра ссылки сортируются по внутреннему идентификатору. Порядок получится стабильным, но для человека случайным: «Яблоко» может оказаться выше «Апельсина».
Два способа получить порядок по наименованию:
// 1. Сравнение по представлению
Таблица.Сортировать("Номенклатура", Новый СравнениеЗначений);
// 2. Отдельная строковая колонка с наименованием
Таблица.Сортировать("НоменклатураНаименование");
Первый способ короче, но платформе приходится получать представление каждой ссылки. На десятках тысяч строк разница заметна. Второй способ быстрее, если наименование уже выбрано в запросе.
Колонка без типа
Колонку можно добавить без ОписаниеТипов. Тогда в ней лежат значения любых типов: числа вперемешку со строками и Неопределено. Порядок такой смеси трудно предсказать и объяснить пользователю. Задавайте тип колонки при создании таблицы, особенно если по ней потом сортируют.
Свой порядок сортировки: служебная колонка-ключ
В 1С нельзя передать в Сортировать свою функцию сравнения, как в некоторых других языках. Приём практиков — добавить служебную колонку, рассчитать в ней «вес» строки, отсортировать по ней и удалить колонку.
Пример: статусы в заданном порядке
Нужно вывести заказы так: сначала «Просрочен», затем «В работе», затем «Выполнен». По алфавиту такой порядок не получить.
Веса = Новый Соответствие;
Веса.Вставить("Просрочен", 1);
Веса.Вставить("В работе", 2);
Веса.Вставить("Выполнен", 3);
Таблица.Колонки.Добавить("ВесСтатуса", Новый ОписаниеТипов("Число"));
Для Каждого Строка Из Таблица Цикл
Вес = Веса.Получить(Строка.Статус);
Строка.ВесСтатуса = ?(Вес = Неопределено, 99, Вес);
КонецЦикла;
Таблица.Сортировать("ВесСтатуса, ДатаЗаказа");
Таблица.Колонки.Удалить("ВесСтатуса");
Неизвестные статусы получают вес 99 и уходят в конец, а не ломают сортировку.
Другие варианты ключа
Тот же приём решает много задач:
- 📏 по длине строки —
Строка.Ключ = СтрДлина(Строка.Наименование);; - 📅 по месяцу без учёта дня —
Строка.Ключ = НачалоМесяца(Строка.Дата);; - 🔢 по числовой части артикула — вынести число в отдельную колонку;
- 🧮 по модулю суммы —
Строка.Ключ = Макс(Строка.Сумма, -Строка.Сумма);.
Реквизит ссылки: артикул, код, родитель
В строке колонок нельзя писать путь через точку: Таблица.Сортировать("Номенклатура.Артикул") не сработает, метод ждёт имя колонки таблицы. Нужен реквизит — выберите его отдельной колонкой.
Лучший вариант — сразу в запросе: Товары.Номенклатура.Артикул КАК Артикул. Если таблица уже собрана в коде, заполните колонку циклом:
Таблица.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
Для Каждого Строка Из Таблица Цикл
Строка.Артикул = Строка.Номенклатура.Артикул;
КонецЦикла;
Таблица.Сортировать("Артикул");
Обращение Строка.Номенклатура.Артикул в цикле — это отдельное чтение из базы на каждую строку. На сотне строк незаметно, на десятках тысяч — медленно. Для больших таблиц получите реквизиты одним запросом: передайте таблицу параметром, поместите во временную таблицу и соедините со справочником.
Дата со временем
Дата в 1С хранит и время. Два документа одного дня с разным временем при сортировке по Дата встанут по времени, а не «как попало». Если нужен порядок по дню, а внутри дня — по сумме, заведите колонку День = НачалоДня(Строка.Дата) и сортируйте по "День, Сумма Убыв".
Сохранить исходный порядок при равных значениях
Документация не обещает, что строки с одинаковым ключом сохранят прежнюю очерёдность. Если это важно — например, строки уже стоят в хронологическом порядке, — зафиксируйте его колонкой-номером:
Таблица.Колонки.Добавить("ИсходныйПорядок", Новый ОписаниеТипов("Число"));
Для Каждого Строка Из Таблица Цикл
Строка.ИсходныйПорядок = Таблица.Индекс(Строка);
КонецЦикла;
Таблица.Сортировать("Категория, ИсходныйПорядок");
Последняя колонка разрешает все «ничьи», и результат всегда одинаковый.
Сортировка в запросе до выгрузки в таблицу значений
Если таблица получена запросом, порядок дешевле задать в самом запросе. СУБД сортирует быстрее, чем код на встроенном языке перебирает строки.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Контрагент КАК Контрагент,
| СУММА(Продажи.Сумма) КАК Сумма
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|СГРУППИРОВАТЬ ПО
| Продажи.Контрагент
|УПОРЯДОЧИТЬ ПО
| Сумма УБЫВ,
| Контрагент";
Таблица = Запрос.Выполнить().Выгрузить();
Имя регистра здесь условное — подставьте свой объект метаданных. Порядок строк в выгруженной таблице будет таким, как в УПОРЯДОЧИТЬ ПО.
Особенности запроса, которые отличают его от метода Сортировать:
- 🔗 упорядочивание по полю-ссылке идёт по представлению объекта, а не по идентификатору. Для справочника это обычно наименование или код;
- ⚙️
АВТОУПОРЯДОЧИВАНИЕподставляет порядок, заданный для объектов в конфигураторе; - 📦 порядок гарантирует только
УПОРЯДОЧИТЬ ПОв итоговом запросе пакета. Сортировка во временной таблице на результат не влияет; - 🔝
ВЫБРАТЬ ПЕРВЫЕ 10вместе сУПОРЯДОЧИТЬ ПО Сумма УБЫВдаёт топ-10 без сортировки всей выборки в коде.
| Способ | Когда выбирать | Ограничения |
|---|---|---|
УПОРЯДОЧИТЬ ПО в запросе | данные приходят из базы | порядок фиксируется на момент выборки |
Сортировать | таблица собрана или изменена в коде | ссылки — по идентификатору без СравнениеЗначений |
Служебная колонка + Сортировать | нужен нестандартный порядок | лишний цикл по строкам |
Отсортировать таблицу значений на управляемой форме
Таблица значений на форме хранится как реквизит, и в коде формы это уже ДанныеФормыКоллекция. Самый надёжный путь — сортировать на сервере через преобразование:
&НаСервере
Процедура ОтсортироватьНаСервере()
Таблица = РеквизитФормыВЗначение("Товары");
Таблица.Сортировать("Сумма Убыв, Номенклатура");
ЗначениеВРеквизитФормы(Таблица, "Товары");
КонецПроцедуры
&НаКлиенте
Процедура Отсортировать(Команда)
ОтсортироватьНаСервере();
КонецПроцедуры
После обратной записи текущая строка табличного поля сбрасывается. Если пользователь стоял на конкретной строке, запомните её ключевые значения до сортировки и найдите строку заново после.
Сортировка табличной части документа меняет номера строк. Если на номера строк ссылаются другие данные — например, связанные табличные части по НомерСтроки или ключ связи, — проверьте, что связь держится не на позиции строки.
Ошибки при сортировке таблицы значений
Т = Т.Сортировать(...). Метод ничего не возвращает. Вызывайте его отдельной строкой.Таблица.Колонки.Найти(...) перед сортировкой.Новый СравнениеЗначений или сортируйте по колонке с наименованием.&НаСервере.Ещё несколько практических замечаний:
- 🔄 не сортируйте таблицу внутри цикла
Для Каждогопо этой же таблице: строки переставятся, и обход пойдёт непредсказуемо; - 🐢 не вызывайте
Сортироватьпосле каждогоДобавить(). Соберите таблицу целиком и отсортируйте один раз; - 🧾 индексы, созданные через
Таблица.Индексы.Добавить(), ускоряютНайтииНайтиСтроки, но на порядок строк не влияют.
Частые вопросы
Как отсортировать таблицу значений по убыванию?
Таблица.Сортировать("Сумма Убыв");. Для нескольких колонок направление задают у каждой отдельно.Можно ли быстро получить максимальное значение без сортировки?
Таблица.Итог("Сумма"), а максимум удобнее найти циклом или в запросе через МАКСИМУМ. Сортировать всю таблицу ради одного значения не нужно.Как развернуть текущий порядок строк в обратную сторону?
Убыв. Отдельного метода для разворота у таблицы значений нет.Как гарантированно отсортировать строки без учёта регистра?
ВРег(Наименование) и сортируйте по ней. Тогда «альфа» и «Альфа» окажутся рядом при любых данных.Сколько строк можно сортировать без проблем?
СравнениеЗначений по ссылкам и память сервера при очень больших выборках.