При работе с результатами запросов в платформе 1С:Предприятие у начинающих разработчиков часто возникает вопрос: как узнать порядковый номер текущей записи при обходе выборки? Нередко за номер строки ошибочно принимают метод Уровень() объекта ВыборкаИзРезультатаЗапроса. Выясним причину этого заблуждения, разберем точное назначение метода Уровень() и рассмотрим правильные практические способы получения номера строки.
Метод Уровень() не имеет никакого отношения к порядковому номеру записи (индексу строки). Он предназначен исключительно для определения глубины текущей записи в иерархических структурах и многоуровневых группировках, созданных с помощью предложений ИТОГИ или ИЕРАРХИЯ.
Проанализируем поведение этого метода в различных ситуациях:
ИТОГИ, а обход выполняется методом РезультатЗапроса.Выбрать(), то для абсолютно каждой записи метод Выборка.Уровень() вернет значение 0.0, группировки первого уровня — 1, детальных записей — 2.Таким образом, использовать Выборка.Уровень() в качестве счетчика строк нельзя. В объекте ВыборкаИзРезультатаЗапроса также отсутствуют встроенные свойства вроде НомерСтроки или Индекс, а в языке запросов 1С нет прямых аналогов оконной функции ROW_NUMBER().
Разберем наиболее простой, надежный и высокопроизводительный способ получения номера строки. Для этого перед началом цикла обхода выборки мы объявляем числовую переменную, а внутри цикла инкрементируем ее на каждой итерации.
Посмотрим на пример реализации:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Номенклатура,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
НомерСтроки = 0;
Пока Выборка.Следующий() Цикл
НомерСтроки = НомерСтроки + 1;
// Используем полученный номер в алгоритме
Сообщить("Строка № " + НомерСтроки + ": " + Выборка.Номенклатура);
КонецЦикла;
КонецЕсли;
Преимущества: данный подход работает с минимальными затратами оперативной памяти и процессорного времени, так как данные считываются последовательно без предварительного создания промежуточных коллекций.
Если для решения задачи требуется коллекция с возможностью прямого доступа к строкам по индексу, результат запроса можно выгрузить в объект ТаблицаЗначений.
Рассмотрим код выгрузки и работы с индексами строк:
РезультатЗапроса = Запрос.Выполнить();
ТаблицаДанных = РезультатЗапроса.Выгрузить();
// Вариант А: получение номера через метод Индекс()
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
// Индексация в ТаблицеЗначений начинается с 0, поэтому прибавляем 1
ТекущийНомер = ТаблицаДанных.Индекс(СтрокаТЗ) + 1;
Сообщить("Номер строки: " + ТекущийНомер);
КонецЦикла;
// Вариант Б: добавление явной колонки с номером
ТаблицаДанных.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число"));
Счетчик = 0;
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
Счетчик = Счетчик + 1;
СтрокаТЗ.НомерСтроки = Счетчик;
КонецЦикла;
Ограничение: выгрузка всего объема данных в оперативную память не рекомендуется при обработке сотен тысяч или миллионов записей, чтобы избежать повышенного потребления ресурсов сервера.
Если данные запроса выводятся в отчет или динамическую форму через систему компоновки данных, нумеровать строки вручную в коде не требуется. В СКД предусмотрены встроенные функции языка выражений:
НомерПоПорядку() — формирует сквозную непрерывную нумерацию строк по всему отчету.НомерПоПорядкуВГруппировке() — вычисляет порядковый номер строки локально в пределах текущей родительской группировки (сбрасывается в 1 при переходе к новой группе).Эти функции достаточно указать в качестве выражения для вычисляемого поля или ресурса на соответствующих вкладках схемы компоновки данных.