Сортировка таблицы значений в 1С 8.3: Сортировать, копия, индексы и запрос
Содержание
Таблицу значений в 1С 8.3 упорядочивают методом Сортировать(): ТЗ.Сортировать("Дата Убыв, Сумма");. Метод меняет порядок строк в самой таблице и ничего не возвращает. Отдельного метода «Упорядочить» у таблицы значений нет: слово УПОРЯДОЧИТЬ ПО живёт в языке запросов.
Частая боль: код выгрузил данные, а строки идут вразнобой, или после сортировки «сломался» исходный порядок, который был нужен в другом месте. Решение зависит от того, откуда пришли данные и нужен ли исходный порядок. Для каждого случая есть свой приём: сортировка на месте, упорядоченная копия, индексы для быстрого поиска и сортировка ещё на уровне запроса.
Метод Сортировать: синтаксис и направления
Синтаксис простой:
ТаблицаЗначений.Сортировать(<Колонки>, <ОбъектСравнения>);
- 📌 Колонки — строка с именами колонок через запятую. После имени можно указать направление:
Возр(по возрастанию) илиУбыв(по убыванию). Без направления — по возрастанию. - 📌 ОбъектСравнения — необязательный параметр типа
СравнениеЗначений. Нужен в основном для ссылочных колонок, подробнее ниже.
Английские синонимы направлений — Asc и Desc. Регистр букв в имени колонки и в направлении значения не имеет.
Пример: сортировка по одной и нескольким колонкам
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
ТЗ.Колонки.Добавить("Склад", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
// ... заполнение строк ...
// Одна колонка, по возрастанию
ТЗ.Сортировать("Дата");
// Несколько колонок: сначала склад по алфавиту,
// внутри склада — от больших сумм к меньшим
ТЗ.Сортировать("Склад Возр, Сумма Убыв");
Порядок колонок в строке задаёт приоритет. Вторая колонка работает только внутри групп с одинаковым значением первой.
Если порядок равных строк для вас важен, не надейтесь на «как было». Добавьте в строку сортировки ещё одну колонку-«разрешитель»: номер, дату или код.
Что важно знать о поведении метода
| Особенность | Что это значит на практике |
|---|---|
| Сортирует на месте | Исходный порядок строк теряется |
| Ничего не возвращает | Запись НоваяТЗ = ТЗ.Сортировать(...) ошибочна: в переменной будет Неопределено |
| Работает по колонкам таблицы | Сортировать по выражению нельзя, только по существующей колонке |
| Выполняется там, где есть таблица значений | На тонком клиенте типа ТаблицаЗначений нет, сортируют на сервере |
Самая частая ошибка новичка — присвоить результат Сортировать() переменной и потом обращаться к ней как к таблице. Метод процедурный, результат всегда в исходном объекте.
Как получить упорядоченную копию и не трогать исходную таблицу
Иногда исходная таблица нужна в прежнем порядке: например, она уже связана с табличной частью документа по номерам строк. Тогда сначала делают копию, а сортируют уже её.
// Полная копия: все строки, все колонки
ТЗОтсортированная = ТЗ.Скопировать();
ТЗОтсортированная.Сортировать("Сумма Убыв");
Скопировать() принимает два необязательных параметра: массив строк (или структуру отбора) и строку с именами колонок. Так можно за один шаг взять только нужное.
// Только строки по складу «Основной» и только две колонки
Отбор = Новый Структура("Склад", "Основной");
ТЗСклад = ТЗ.Скопировать(Отбор, "Дата, Сумма");
ТЗСклад.Сортировать("Дата");
Упорядоченный итог по группам
Когда нужны не все строки, а суммы по группам, удобнее свернуть таблицу и только потом сортировать. Свернуть() тоже работает на месте, поэтому сворачивают копию.
Итоги = ТЗ.Скопировать(, "Склад, Сумма");
Итоги.Свернуть("Склад", "Сумма");
Итоги.Сортировать("Сумма Убыв");
// Первая строка — склад с наибольшей суммой
Топ-N строк после сортировки
Методов «первые N строк» у таблицы значений нет. Обрезают с конца обратным циклом, чтобы индексы не съезжали:
ТЗ.Сортировать("Сумма Убыв");
Оставить = 10;
Всего = ТЗ.Количество();
Для Сч = 1 По Всего - Оставить Цикл
ТЗ.Удалить(ТЗ.Количество() - 1);
КонецЦикла;
Если строк меньше десяти, цикл не выполнится ни разу: Всего - Оставить будет меньше единицы.
Упорядочить табличную часть документа
Частая задача — расставить строки табличной части по номенклатуре или сумме. Табличную часть выгружают в таблицу значений, сортируют и загружают обратно:
ТЗТовары = ДокументОбъект.Товары.Выгрузить();
ТЗТовары.Сортировать("Сумма Убыв");
ДокументОбъект.Товары.Загрузить(ТЗТовары);
При загрузке номера строк идут в новом порядке, начиная с первого. Изменения попадут в базу только после записи документа.
Индексы таблицы значений: что ускоряют, а что нет
Метода «Индексировать» у таблицы значений тоже нет. Индексы добавляют через коллекцию Индексы:
ТЗ.Индексы.Добавить("Номенклатура, Склад");
Индекс ускоряет поиск, а не сортировку. Его используют методы НайтиСтроки() с отбором по проиндексированным колонкам и Найти().
- ✅ Индекс полезен, когда по большой таблице много раз ищут строки в цикле: тысячи вызовов
НайтиСтроки(). - ❌ Индекс не меняет порядок строк. После его добавления
Для Каждогообходит строки в прежнем порядке. - ❌ Индекс не ускоряет
Сортировать(). - ⚠️ Индекс занимает память и пересчитывается при добавлении и изменении строк. На таблице из 50 строк он не нужен.
Как индекс сочетается с отбором
ТЗ.Индексы.Добавить("Номенклатура, Склад");
Для Каждого СтрокаДокумента Из Документ.Товары Цикл
Отбор = Новый Структура("Номенклатура, Склад",
СтрокаДокумента.Номенклатура, СтрокаДокумента.Склад);
Найденные = ТЗ.НайтиСтроки(Отбор);
// работа с найденными строками
КонецЦикла;
Набор полей в структуре отбора должен совпадать с колонками индекса. Тогда поиск идёт по индексу, а не перебором всех строк.
Добавляйте индекс один раз, после заполнения таблицы и до цикла поиска. Если добавить его до массовой загрузки строк, платформа будет поддерживать его на каждой вставке.
Сравнение способов: когда сортировать, копировать или индексировать
| Способ | Когда подходит | Чем рискуете |
|---|---|---|
ТЗ.Сортировать() | Таблица нужна только в новом порядке | Теряется исходный порядок строк |
Скопировать() + Сортировать() | Исходная таблица нужна без изменений | Двойной расход памяти на больших таблицах |
Скопировать() + Свернуть() + Сортировать() | Нужен упорядоченный итог по группам | Колонки, не указанные в Свернуть, пропадут |
Индексы.Добавить() | Частый поиск строк по одним и тем же колонкам | Лишняя память; на порядок строк не влияет |
УПОРЯДОЧИТЬ ПО в запросе | Данные приходят из базы | Порядок временных таблиц не гарантируется |
СписокЗначений.СортироватьПоЗначению() | Нужно упорядочить одномерный набор значений | Подходит только для одной колонки |
Простое правило: если данные берутся из базы, упорядочивайте в запросе. Если таблица собрана в коде или прошла обработку, сортируйте её методом Сортировать().
Если нужен массив, а не таблица
У массива метода сортировки нет. Значения перекладывают в список значений, сортируют и выгружают обратно:
Список = Новый СписокЗначений;
Список.ЗагрузитьЗначения(МассивСумм);
Список.СортироватьПоЗначению(НаправлениеСортировки.Убыв);
МассивСумм = Список.ВыгрузитьЗначения();
Для одной колонки таблицы годится связка ВыгрузитьКолонку() → список значений → сортировка.
Сортировка в запросе до выгрузки в таблицу значений
Когда таблица значений получается через Запрос.Выполнить().Выгрузить(), проще отдать упорядочивание СУБД. Это быстрее, чем сортировать десятки тысяч строк в памяти сервера 1С.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Контрагент КАК Контрагент,
| Продажи.Контрагент.Наименование КАК КонтрагентНаименование,
| СУММА(Продажи.Сумма) КАК Сумма
|ИЗ
| ВременнаяТаблицаПродаж КАК Продажи
|СГРУППИРОВАТЬ ПО
| Продажи.Контрагент,
| Продажи.Контрагент.Наименование
|УПОРЯДОЧИТЬ ПО
| Сумма УБЫВ,
| КонтрагентНаименование";
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
ТЗ = Запрос.Выполнить().Выгрузить();
Здесь ВременнаяТаблицаПродаж — временная таблица, созданная раньше в том же менеджере. Направления в запросе пишут так же: ВОЗР и УБЫВ.
Три правила упорядочивания в запросе
- Сортируйте в последнем запросе пакета. Если поставить
УПОРЯДОЧИТЬ ПОв запрос сПОМЕСТИТЬ, порядок строк временной таблицы при чтении не гарантирован. - Для алфавитного порядка указывайте реквизит явно. Вместо поля-ссылки
КонтрагентпишитеКонтрагент.НаименованиеилиКонтрагент.Код. Так результат предсказуем. - Ключевое слово
АВТОУПОРЯДОЧИВАНИЕдобавляет к порядку поля, принятые для объекта по умолчанию. Удобно в отчётах, но в коде лучше задавать порядок явно.
Если после выгрузки вы добавляете строки или сворачиваете таблицу, порядок из запроса может нарушиться. Тогда сортируйте в коде повторно.
Ссылки, вычисляемые поля и формы: нестандартные случаи
Колонка со ссылками на справочник
Если в колонке ссылки, обычный Сортировать("Контрагент") не даёт алфавитного порядка по наименованию. Есть два пути:
- 🔹 Передать объект сравнения:
ТЗ.Сортировать("Контрагент", Новый СравнениеЗначений);. Это сравнение ссылок по представлению, на большой таблице оно медленное: представления приходится получать из базы. - 🔹 Заранее положить наименование в отдельную строковую колонку (из запроса или в цикле) и сортировать по ней. На больших объёмах это быстрее и прозрачнее.
Сортировка по вычисляемому значению
Сортировать по выражению метод не умеет. Приём практика — временная колонка:
ТЗ.Колонки.Добавить("Маржа", Новый ОписаниеТипов("Число"));
Для Каждого Стр Из ТЗ Цикл
Стр.Маржа = Стр.Выручка - Стр.Себестоимость;
КонецЦикла;
ТЗ.Сортировать("Маржа Убыв");
ТЗ.Колонки.Удалить("Маржа");
Колонку удаляют сразу после сортировки, если она не нужна дальше: порядок строк при этом сохраняется.
Числа, сохранённые строкой
Если колонка создана без типа и заполнена текстом из файла, значения "10" и "9" сравниваются как строки: "10" окажется раньше "9". Решение — при создании колонки задать тип Новый ОписаниеТипов("Число") и записывать в неё числа, а не строки.
С датами то же самое: строка "01.02.2025" и значение типа Дата упорядочиваются по-разному. Пустые значения обычно оказываются в начале при сортировке по возрастанию; проверьте это на своих данных, если пустые строки мешают.
Таблица на управляемой форме
На форме таблица значений хранится как реквизит типа ДанныеФормыКоллекция. Надёжный путь — сортировка на сервере:
&НаСервере
Процедура УпорядочитьНаСервере()
ТЗ = РеквизитФормыВЗначение("Таблица");
ТЗ.Сортировать("Дата Убыв");
ЗначениеВРеквизитФормы(ТЗ, "Таблица");
КонецПроцедуры
Пользователь и сам может упорядочить список щелчком по заголовку колонки, но это меняет только отображение в элементе формы.
Дерево значений
У дерева сортировка вызывается у коллекции строк: Дерево.Строки.Сортировать("Наименование", Истина);. Второй параметр Истина включает сортировку вложенных уровней. Без него упорядочатся только строки верхнего уровня.
Ошибки при упорядочивании таблицы значений
Сортировка внутри цикла по той же таблице
Не вызывайте Сортировать() внутри Для Каждого по этой же таблице. Обход идёт по позициям, и после перестановки строк часть из них будет пропущена, а часть обработана дважды. Сначала сортировка, потом цикл.
Частые вопросы
Сохраняется ли порядок строк с одинаковыми значениями после Сортировать?
Можно ли отсортировать таблицу значений по колонке, которой нет в выборке?
Как упорядочить таблицу значений случайным образом?
Новый ГенераторСлучайныхЧисел и отсортируйте по ней.