Метод Сортировать у ТаблицыЗначений: колонки, направления, свой порядок и запрос

· 9 мин

Содержание

Таблицу значений сортируют одной строкой: Таблица.Сортировать("Сумма Убыв");. В параметре перечисляют колонки через запятую, после имени колонки через пробел ставят направление — Возр или Убыв. Без направления платформа сортирует по возрастанию. Метод меняет саму таблицу и ничего не возвращает.

Типичная ситуация: разработчик собирает в коде остатки по складам, сворачивает их и выводит в печатную форму, а заказчик просит «сначала крупные суммы, внутри — по алфавиту». Это решается сортировкой по двум колонкам. Сложнее, когда нужен нестандартный порядок: статусы в своей последовательности, ссылки по наименованию, даты внутри групп. Всё это тоже делается штатными средствами 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 без сортировки всей выборки в коде.
СпособКогда выбиратьОграничения
УПОРЯДОЧИТЬ ПО в запроседанные приходят из базыпорядок фиксируется на момент выборки
Сортироватьтаблица собрана или изменена в кодессылки — по идентификатору без СравнениеЗначений
Служебная колонка + Сортироватьнужен нестандартный порядоклишний цикл по строкам

Отсортировать таблицу значений на управляемой форме

Таблица значений на форме хранится как реквизит, и в коде формы это уже ДанныеФормыКоллекция. Самый надёжный путь — сортировать на сервере через преобразование:

&НаСервере
Процедура ОтсортироватьНаСервере()
    Таблица = РеквизитФормыВЗначение("Товары");
    Таблица.Сортировать("Сумма Убыв, Номенклатура");
    ЗначениеВРеквизитФормы(Таблица, "Товары");
КонецПроцедуры

&НаКлиенте
Процедура Отсортировать(Команда)
    ОтсортироватьНаСервере();
КонецПроцедуры

После обратной записи текущая строка табличного поля сбрасывается. Если пользователь стоял на конкретной строке, запомните её ключевые значения до сортировки и найдите строку заново после.

Сортировка табличной части документа меняет номера строк. Если на номера строк ссылаются другие данные — например, связанные табличные части по НомерСтроки или ключ связи, — проверьте, что связь держится не на позиции строки.

Ошибки при сортировке таблицы значений

Диагностика: выберите симптом

Ещё несколько практических замечаний:

  • 🔄 не сортируйте таблицу внутри цикла Для Каждого по этой же таблице: строки переставятся, и обход пойдёт непредсказуемо;
  • 🐢 не вызывайте Сортировать после каждого Добавить(). Соберите таблицу целиком и отсортируйте один раз;
  • 🧾 индексы, созданные через Таблица.Индексы.Добавить(), ускоряют Найти и НайтиСтроки, но на порядок строк не влияют.

Частые вопросы

Как отсортировать таблицу значений по убыванию?
Укажите направление после имени колонки: Таблица.Сортировать("Сумма Убыв");. Для нескольких колонок направление задают у каждой отдельно.
Можно ли быстро получить максимальное значение без сортировки?
Для числовой колонки сумму даёт Таблица.Итог("Сумма"), а максимум удобнее найти циклом или в запросе через МАКСИМУМ. Сортировать всю таблицу ради одного значения не нужно.
Как развернуть текущий порядок строк в обратную сторону?
Добавьте колонку с индексом строки и отсортируйте по ней с Убыв. Отдельного метода для разворота у таблицы значений нет.
Как гарантированно отсортировать строки без учёта регистра?
Добавьте служебную колонку со значением ВРег(Наименование) и сортируйте по ней. Тогда «альфа» и «Альфа» окажутся рядом при любых данных.
Сколько строк можно сортировать без проблем?
Таблица значений целиком лежит в памяти сервера. Десятки тысяч строк сортируются быстро. Узкое место обычно не сама сортировка, а СравнениеЗначений по ссылкам и память сервера при очень больших выборках.