К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как пронумеровать строки в запросе 1С

Как пронумеровать строки в запросе 1С: нумерация через временные таблицы, АВТОНОМЕРЗАПИСИ, обход выборки и нумерация в СКД. Примеры кода и типичные ошибки.

Пронумеровать строки результата запроса в 1С — частая задача: она нужна для отчётов, печатных форм, выгрузок и сопоставления данных. Проблема в том, что в языке запросов 1С нет встроенной функции нумерации строк вроде ROW_NUMBER() из стандартного SQL. Поэтому разработчики используют обходные приёмы, каждый из которых имеет свои ограничения.

Основных подхода четыре: нумерация при обходе выборки в коде, использование функции АВТОНОМЕРЗАПИСИ(), классический приём с соединением таблицы самой с собой и подсчётом строк, а также нумерация средствами СКД, если результат выводится в отчёт. Выбор зависит от того, где нужен номер — в самом запросе, в коде или в макете.

Ниже разобраны все способы с примерами кода, условиями применения и типичными ошибками. Отдельно рассмотрены нумерация внутри групп и проверка корректности результата.

Способ 1. Нумерация при обходе выборки в коде

Самый простой и надёжный вариант — не нумеровать в запросе вообще, а присвоить номера при обходе результата. Запрос остаётся простым, а счётчик ведётся в коде на встроенном языке.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Товар,

| Номенклатура.Наименование КАК Наименование

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления

|УПОРЯДОЧИТЬ ПО

| Наименование";

Выборка = Запрос.Выполнить().Выбрать();

НомерСтроки = 0;

Пока Выборка.Следующий() Цикл

НомерСтроки = НомерСтроки + 1;

// НомерСтроки — порядковый номер текущей строки

КонецЦикла;

Этот способ подходит, когда нумерация нужна для печатной формы, табличного документа, файла выгрузки или заполнения таблицы значений. Он не нагружает СУБД дополнительными соединениями и работает быстро даже на больших выборках.

Важно помнить: номер присваивается в порядке обхода, поэтому порядок строк должен быть явно задан конструкцией УПОРЯДОЧИТЬ ПО. Без упорядочивания СУБД может вернуть строки в произвольном порядке, и нумерация окажется непредсказуемой от запуска к запуску.

Способ 2. Функция АВТОНОМЕРЗАПИСИ()

В языке запросов 1С есть функция АВТОНОМЕРЗАПИСИ(), которая возвращает уникальный номер записи в виртуальной таблице. Формально её можно использовать для получения числового идентификатора строки.

ВЫБРАТЬ

АВТОНОМЕРЗАПИСИ() КАК Номер,

Товары.Номенклатура КАК Номенклатура

ИЗ

Документ.РеализацияТоваровУслуг.Товары КАК Товары

Однако у этого подхода есть принципиальное ограничение: автономер присваивается внутренним механизмом платформы и не гарантирует ни последовательность без пропусков, ни соответствие порядку сортировки. Номера могут идти не с единицы и не подряд.

Практическая область применения АВТОНОМЕРЗАПИСИ() — получение уникального технического ключа строки, когда важна только уникальность, а не красивый порядок. Например, для связи временных таблиц, где нет другого уникального идентификатора.

Способ 3. Нумерация через самосоединение таблицы

Классический приём «чистого SQL», который работает и в 1С: соединить выборку саму с собой и подсчитать количество строк, значение упорядочивающего поля которых меньше или равно текущему. Количество таких строк и есть номер.

ВЫБРАТЬ

Таб.Номенклатура КАК Номенклатура

ПОМЕСТИТЬ ВТ_Данные

ИЗ

&ТаблицаТоваров КАК Таб

;

ВЫБРАТЬ

Т1.Номенклатура КАК Номенклатура,

КОЛИЧЕСТВО(Т2.Номенклатура) КАК НомерСтроки

ИЗ

ВТ_Данные КАК Т1

ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2

ПО Т2.Номенклатура <= Т1.Номенклатура

СГРУППИРОВАТЬ ПО

Т1.Номенклатура

УПОРЯДОЧИТЬ ПО

НомерСтроки

Логика такая: для каждой строки считаем, сколько строк имеют значение ключа меньше или равно её ключу. Поле, по которому идёт сравнение, должно быть уникальным — иначе одинаковые значения получат одинаковый номер, и нумерация «схлопнется».

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

Способ 4. Нумерация в отчётах на СКД

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

Порядок действий в СКД
  1. 1
    Откройте схему компоновки данных и перейдите на вкладку «Вычисляемые поля»
  2. 2
    Добавьте поле «НомерСтроки» с выражением: НомерПоПорядку() или порядковый номер через функцию ВычислитьВыражение
  3. 3
    Добавьте поле в ресурсы или в выбранные поля отчёта с нужной позицией в списке колонок
  4. 4
    Проверьте отчёт: номера должны идти подряд с единицы в порядке сортировки отчёта

Для нумерации внутри группировок применяется функция ВычислитьВыражение с параметром группировки. Например, выражение вида «ВычислитьВыражение("НомерПоПорядку()", , "Первая", "Текущая")» позволяет получить номер строки в пределах текущей группы, что удобно для печатных форм с разбивкой по контрагентам или складам.

Также в макетах табличных документов при программном выводе номер строки обычно передают параметром из того же счётчика обхода — это самый прозрачный вариант для печатных форм.

Нумерация строк внутри групп

Отдельная задача — пронумеровать строки не сквозным образом, а внутри каждой группы: например, товары внутри каждого документа или строки по каждому контрагенту. В запросе это решается модификацией приёма с самосоединением: в условие соединения добавляется равенство группировочного поля.

ВЫБРАТЬ

Т1.Документ КАК Документ,

Т1.Товар КАК Товар,

КОЛИЧЕСТВО(Т2.Товар) КАК НомерВГруппе

ИЗ

ВТ_Данные КАК Т1

ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2

ПО Т2.Документ = Т1.Документ

И Т2.Товар <= Т1.Товар

СГРУППИРОВАТЬ ПО

Т1.Документ,

Т1.Товар

При обходе выборки в коде групповая нумерация делается сбросом счётчика при смене группы. Для этого используют обход по группировкам (Выбрать с типом обхода «ПоГруппировкам») либо сравнение значения группового поля с предыдущим.

Маршрут решения

Как выбрать способ нумерации

Номер нужен в коде, печатной форме или выгрузкеНумеруйте счётчиком при обходе выборки — это быстро и надёжно
Номер нужен прямо в тексте запроса для дальнейших соединенийИспользуйте самосоединение с КОЛИЧЕСТВО по уникальному упорядочивающему полю
Нужен только уникальный технический ключ строкиПодойдёт АВТОНОМЕРЗАПИСИ(), но не ждите от неё последовательных номеров
Результат выводится отчётом на СКДДобавьте вычисляемое поле с НомерПоПорядку() или ВычислитьВыражение

Проверка результата и типичные ошибки

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

Контрольные точки

Как проверить результат

Первый номер в выборке
Норма

Нумерация начинается с 1

Тревожный признак

Номера начинаются с произвольного значения — вероятно, использована АВТОНОМЕРЗАПИСИ

Непрерывность номеров
Норма

Каждый следующий номер больше предыдущего ровно на 1

Тревожный признак

Есть пропуски или дубли — ключ упорядочивания не уникален

Совпадение с сортировкой
Норма

Номера растут в том же порядке, что задан в УПОРЯДОЧИТЬ ПО

Тревожный признак

Номера идут вразнобой — порядок обхода не зафиксирован сортировкой

Типичные ошибки
01
Нумерация без УПОРЯДОЧИТЬ ПО — порядок строк не гарантирован, номера «плавают» между запусками
02
Самосоединение по неуникальному полю — одинаковые значения получают один номер, итоговая нумерация с пропусками
03
Использование АВТОНОМЕРЗАПИСИ для пользовательской нумерации — номера с пропусками и не с единицы
04
Самосоединение на больших таблицах без необходимости — квадратичный рост времени выполнения, хотя счётчик в коде решил бы задачу мгновенно
05
Смешение сквозной и групповой нумерации — счётчик не сбрасывается при смене группы

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

Итог

Что важно запомнить

Прямой функции нумерации в запросах 1С нет. В большинстве случаев правильное решение — счётчик при обходе выборки. В самом запросе используйте самосоединение с КОЛИЧЕСТВО по уникальному полю, в СКД — вычисляемое поле. АВТОНОМЕРЗАПИСИ даёт только уникальность, но не красивую последовательность. Всегда фиксируйте порядок строк конструкцией УПОРЯДОЧИТЬ ПО.

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

Можно ли пронумеровать строки запроса без соединения таблиц?

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

Почему АВТОНОМЕРЗАПИСИ даёт номера не подряд?

Функция возвращает внутренний технический номер записи виртуальной таблицы, который платформа присваивает по своим правилам. Он гарантирует только уникальность, но не последовательность и не старт с единицы.

Как пронумеровать строки табличной части документа?

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

Какой способ быстрее на больших объёмах?

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

Как сделать нумерацию в динамическом списке?

В динамическом списке добавить вычисляемый номер строки штатно нельзя, так как его запрос формируется платформой. Обычно выводят колонку со стандартным номером строки либо переводят вывод на отчёт СКД, где доступно вычисляемое поле.

Нужно ли индексировать поле для самосоединения?

Если нумеруется временная таблица, полезно проиндексировать поле, по которому идёт соединение, с помощью конструкции ИНДЕКСИРОВАТЬ ПО. Это заметно ускоряет соединение на заметных объёмах данных.