При выполнении метода Выгрузить() объекта РезультатЗапроса платформа 1С формирует колонки объекта ТаблицаЗначений строго на основании полей, указанных в секции ВЫБРАТЬ. В отличие от табличных частей документов или справочников, у объекта ТаблицаЗначений нет встроенного системного реквизита НомерСтроки.
Кроме того, в языке запросов 1С отсутствуют аналитические (оконные) функции (такие как ROW_NUMBER() OVER() в SQL), поэтому получить порядковый номер записи прямо при выборке без дополнительных ухищрений не удается.
Рассмотрим основные способы решения этой задачи, их особенности и влияние на производительность.
Наиболее эффективным и безопасным подходом с точки зрения производительности является сочетание подготовки колонки в самом запросе и последующего быстрого обхода таблицы по индексу.
Разберем по шагам алгоритм действий:
ВЫБРАТЬ языка запросов сразу добавляем числовое поле-заглушку, например 0 КАК НомерСтроки. В этом случае выгруженная ТаблицаЗначений сразу получит колонку с нужным именем и типом данных Число, и нам не придется вызывать метод ТЗ.Колонки.Добавить().Проанализируем пример кода 1С для этого решения:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| 0 КАК НомерСтроки,
| Номенклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
ТЗ = Запрос.Выполнить().Выгрузить();
Для Индекс = 0 По ТЗ.Количество() - 1 Цикл
ТЗ[Индекс].НомерСтроки = Индекс + 1;
КонецЦикла;
Важный момент по производительности: заполнение по индексу выполняется с вычислительной сложностью $O(N)$, где $N$ — количество строк. Не используйте метод ТЗ.Индекс(Стр) внутри обхода Для Каждого Строка Из ТЗ Цикл, так как вызов Индекс() на каждом шаге выполняет повторный поиск с начала таблицы, что замедляет работу алгоритма до $O(N^2)$.
Если задача заключается в формировании отчета или выводе данных пользователю, выгоднее задействовать механизм СКД. В Системе компоновки данных предусмотрено системное поле НомерПоПорядку (или СистемныеПоля.НомерПоПорядку).
Рассмотрим, чем этот подход отличается от обычного запроса:
Существует возможность получить нумерацию строк прямо в тексте запроса с помощью левого самосоединения временной таблицы. Однако у этого способа есть существенные ограничения.
Выясним механику работы алгоритма:
ВТ_Данные.ВТ_Данные сама с собой по условию ВТ1.УникальноеПоле >= ВТ2.УникальноеПоле.КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВТ2.УникальноеПоле).Посмотрим на пример текста запроса:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура
ПОМЕСТИТЬ ВТ_Данные
ИЗ
Справочник.Номенклатура КАК Номенклатура
;
ВЫБРАТЬ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Т2.Номенклатура) КАК НомерСтроки,
Т1.Номенклатура КАК Номенклатура
ИЗ
ВТ_Данные КАК Т1
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
ПО Т1.Номенклатура >= Т2.Номенклатура
ГРУППИРОВАТЬ ПО
Т1.Номенклатура
Ограничения этого способа:
Если нумерация нужна исключительно для визуального отображения пользователю в интерфейсе (в элементе формы ТаблицаФормы), добавлять колонку в сам объект ТаблицаЗначений на сервере вовсе не требуется.
Проанализируем этот вариант:
Этот способ экономит оперативную память сервера и ресурс процессора, исключая лишние операции по нумерации данных в коде.