Разработка и Конфигурация · 13 мин
Как в запросе 1С вывести номер строки
Как вывести номер строки в запросе 1С: АВТОНОМЕРЗАПИСИ, нумерация в СКД и в коде. Примеры запросов, ограничения методов, типичные ошибки и ответы на вопросы.
Задача пронумеровать строки результата запроса встречается в 1С постоянно: при построении отчётов, выгрузке данных, формировании печатных форм и сравнении выборок. В языке запросов 1С нет прямой функции ROW_NUMBER(), как в классическом SQL, поэтому разработчики используют несколько обходных путей — от функции АВТОНОМЕРЗАПИСИ до нумерации средствами СКД или встроенного языка.
Выбор способа зависит от контекста: нужен ли номер уже на уровне текста запроса, достаточно ли номера в таблице значений после выполнения запроса, или нумерация требуется только при выводе отчёта. Каждый вариант имеет свои ограничения, и важно понимать их заранее, чтобы не получить неожиданный результат.
Ниже разобраны все рабочие методы с примерами кода, условиями применения и типичными ошибками. Материал ориентирован на платформу 1С:Предприятие 8.3, но большинство приёмов работает и в более ранних версиях линейки 8.
Почему в запросе 1С нет обычного номера строки
Язык запросов 1С построен поверх декларативной логики: результат запроса — это неупорядоченное множество записей до тех пор, пока не задано предложение УПОРЯДОЧИТЬ ПО. Даже с сортировкой платформа не гарантирует стабильный порядок строк при повторном выполнении, если ключи сортировки не уникальны. Поэтому понятие «номер строки» в самом запросе зависит от контекста выполнения.
Это принципиальное отличие от T-SQL или PL/SQL, где оконные функции вроде ROW_NUMBER() OVER (ORDER BY ...) давно стали стандартом. В 1С разработчику приходится выбирать, на каком этапе появляется номер: в запросе, в коде после выполнения или при выводе в отчёт.
Практический вывод: прежде чем искать «номер строки в запросе», определите, где этот номер реально нужен. Если он используется только для отображения пользователю — нумеруйте при выводе. Если номер участвует в дальнейших вычислениях или соединениях — добавляйте его в таблицу значений в коде.
Способ 1. Функция АВТОНОМЕРЗАПИСИ в итогах запроса
Единственная «родная» функция нумерации в языке запросов — АВТОНОМЕРЗАПИСИ. Она возвращает целое число, уникальное для каждой записи результата, но применяется строго в полях итогов, то есть при использовании предложения ИТОГИ.
Пример запроса с нумерацией группировочных записей:
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
АВТОНОМЕРЗАПИСИ() КАК НомерСтроки
ИЗ
Справочник.Номенклатура КАК Товары
ИТОГИ
АВТОНОМЕРЗАПИСИ()
ПО
ОБЩИЕ
Главное ограничение: функция не работает для нумерации детальных строк обычной выборки без итогов. Если попытаться использовать её просто в списке полей без ИТОГИ, конструктор запроса выдаст ошибку. Кроме того, порядок номеров определяется внутренней логикой платформы и не обязан совпадать с визуальным порядком строк после сортировки.
Применять АВТОНОМЕРЗАПИСИ разумно, когда нужен уникальный идентификатор записи внутри результата — например, для временных таблиц, где важна уникальность, а не последовательность. Для «красивой» нумерации 1, 2, 3 по порядку сортировки эта функция не подходит.
Способ 2. Нумерация в таблице значений после выполнения запроса
Самый надёжный и универсальный метод — выполнить запрос в таблицу значений, добавить колонку «НомерСтроки» и заполнить её в цикле. Порядок номеров при этом полностью совпадает с порядком строк в таблице, который определяется сортировкой запроса.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Товар,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|УПОРЯДОЧИТЬ ПО
| Наименование";
ТаблицаРезультат = Запрос.Выполнить().Выгрузить();
ТаблицаРезультат.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число"));
Номер = 0;
Для Каждого СтрокаТаблицы Из ТаблицаРезультат Цикл
Номер = Номер + 1;
СтрокаТаблицы.НомерСтроки = Номер;
КонецЦикла;
Альтернатива без дополнительного счётчика — использовать свойство индекса строки. Метод ТаблицаРезультат.Индекс(СтрокаТаблицы) возвращает индекс с нуля, поэтому номер получается прибавлением единицы. Однако явный счётчик читается проще и работает быстрее на больших таблицах, так как Индекс() выполняет поиск строки.
Если результат обходится через выборку (Выборка = Запрос.Выполнить().Выбрать()), номер удобно вести прямо в цикле обхода — это экономит память, потому что не требуется выгружать весь результат в таблицу значений.
- 1Напишите запрос и обязательно добавьте предложение УПОРЯДОЧИТЬ ПО — без него нумерация будет непредсказуемой
- 2Выполните запрос и выгрузите результат в таблицу значений методом Выгрузить()
- 3Добавьте в таблицу колонку НомерСтроки с типом Число
- 4Пройдите по строкам циклом и присвойте каждой строке значение счётчика
- 5Проверьте: первая строка имеет номер 1, последний номер равен количеству строк таблицы
Способ 3. Номер строки в СКД через вычисляемое поле
В системе компоновки данных нумерацию удобно делать без изменения запроса — через вычисляемое поле. В схеме компоновки на закладке «Вычисляемые поля» добавьте поле с произвольным именем, например НомерСтроки, и укажите выражение:
НомерСтроки()
Функция НомерСтроки() доступна в языке выражений СКД и возвращает порядковый номер записи в текущей группировке вывода. Добавьте это поле в настройки отчёта (выбранные поля) — и каждая строка получит номер автоматически.
Нюансы поведения: функция нумерует записи в рамках текущего уровня группировки, поэтому в отчёте с группами номера будут начинаться заново внутри каждой группы либо продолжаться сквозным образом — в зависимости от того, где размещено поле. Если нужна сквозная нумерация по всему отчёту, выводите поле на уровне общих итогов детальных записей и проверяйте результат на реальных данных.
Преимущество подхода — нумерация не зависит от текста запроса и не требует изменения кода. Недостаток — номер существует только при выводе отчёта и недоступен для программных вычислений в процессоре компоновки.
Сравнение вариантов
Подходит для уникальной идентификации записей в итогах. Ограничение: не работает в детальных строках без ИТОГИ, порядок номеров не привязан к сортировке.
Универсальный способ для кода, выгрузок и обменов. Полный контроль над порядком. Требует выгрузки результата и дополнительного цикла.
Оптимально для отчётов на СКД: ноль изменений в запросе. Номер существует только при выводе, недоступен для дальнейших вычислений.
Подходит для печатных форм и обработки данных потоком без выгрузки в таблицу. Номер доступен только внутри цикла обхода.
Способ 4. Нумерация в динамическом списке и табличном документе
Для динамических списков форм номер строки обычно не добавляют в сам запрос списка — это ломает механизмы платформы (ключи строк, динамическое считывание). Если требуется показать номер, его выводят через событие ПриПолученииДанныхНаСервере или оформление строк, но чаще задачу решают заменой динамического списка на таблицу значений с собственной колонкой номера.
При выводе в табличный документ (печатные формы) нумерация традиционно ведётся счётчиком в цикле обхода выборки:
Выборка = Запрос.Выполнить().Выбрать();
НомерСтроки = 0;
Пока Выборка.Следующий() Цикл
НомерСтроки = НомерСтроки + 1;
ОбластьСтрока.Параметры.НомерСтроки = НомерСтроки;
ОбластьСтрока.Параметры.Заполнить(Выборка);
ТабДокумент.Вывести(ОбластьСтрока);
КонецЦикла;
В макете при этом в области строки должен быть параметр с именем НомерСтроки. Если печатная форма строится на СКД, вернитесь к предыдущему разделу — вычисляемое поле удобнее ручного счётчика.
Как проверить корректность нумерации
После внедрения любого из способов проверьте результат на контрольных признаках. Нумерация считается корректной, если первый номер равен 1, номера идут без пропусков и дублей, а последний номер совпадает с количеством строк результата.
Дополнительно проверьте поведение на граничных случаях: пустой результат запроса (цикл не выполнится, номеров нет — это норма), результат из одной строки, и результат с повторяющимися значениями в поле сортировки. В последнем случае убедитесь, что сортировка детерминирована: добавьте в УПОРЯДОЧИТЬ ПО уникальное поле (например, ссылку), иначе при повторных выполнениях строки с одинаковыми значениями могут меняться местами вместе с номерами.
Для СКД проверка сводится к визуальному контролю: сформируйте отчёт с группировками и без, убедитесь, что нумерация ведёт себя ожидаемо на каждом уровне. Если номера «скачут», проверьте, на каком уровне группировки размещено вычисляемое поле.
Как проверить результат
Первая строка — 1, последняя равна количеству строк
Нумерация начинается с 0 или обрывается раньше конца
Номера идут подряд без пропусков и повторов
Есть пропуски или дубли — значит, счётчик сбрасывается или поле размещено не на том уровне группировки
При той же сортировке номера у строк не меняются
Номера «плавают» — добавьте уникальное поле в УПОРЯДОЧИТЬ ПО
Строк нет, номеров нет, ошибок не возникает
Ошибка обращения к строкам или номер 1 без данных
Типичные ошибки и ограничения
Самая частая ошибка — попытка использовать АВТОНОМЕРЗАПИСИ в обычной выборке без ИТОГИ. Запрос просто не пройдёт проверку, а новички тратят время на поиск обходных вариантов синтаксиса, которых не существует.
Вторая распространённая проблема — нумерация без сортировки. Если в запросе нет УПОРЯДОЧИТЬ ПО, порядок строк технически не определён, и «номер строки» теряет смысл: при следующем выполнении та же запись может получить другой номер.
Третья ошибка — использование метода Индекс() внутри цикла по большой таблице. На таблицах в десятки тысяч строк это заметно замедляет обработку, потому что поиск индекса строки выполняется перебором. Явный счётчик решает задачу за константное время на каждой итерации.
Отдельно отметим ограничение по производительности: добавление колонки и цикл по таблице значений — операция линейной сложности, на практике она незаметна даже на сотнях тысяч строк. Реальные проблемы возникают только при нумерации через соединение запроса самого с собой (приём с подсчётом записей «меньше текущей»), который на больших выборках работает катастрофически медленно. Такой приём встречается в старых публикациях — использовать его в продуктивном коде не следует.
Что важно запомнить
Прямой нумерации строк в языке запросов 1С нет. Для кода — выгружайте результат в таблицу значений и заполняйте колонку номера в цикле; для отчётов на СКД — используйте вычисляемое поле НомерСтроки(); для печатных форм — счётчик при обходе выборки. АВТОНОМЕРЗАПИСИ применяйте только в итогах и не как порядковый номер. Всегда сортируйте результат перед нумерацией.
Частые вопросы
Можно ли пронумеровать строки прямо в тексте запроса без ИТОГИ?
Нет, штатной функции для этого в языке запросов 1С нет. Приёмы с самосоединением и подсчётом записей теоретически возможны, но крайне медленны на реальных объёмах. Практичное решение — выгрузить результат в таблицу значений и добавить колонку номера в цикле либо перенести нумерацию в СКД.
Почему АВТОНОМЕРЗАПИСИ выдаёт номера не по порядку сортировки?
Функция присваивает номера по внутреннему порядку обработки записей платформой, который не совпадает с порядком предложения УПОРЯДОЧИТЬ ПО. Она гарантирует только уникальность номера, но не последовательность относительно сортировки. Для порядковой нумерации используйте счётчик в коде или вычисляемое поле СКД.
Как пронумеровать строки в отчёте на СКД без изменения запроса?
Добавьте в схеме компоновки на закладке «Вычисляемые поля» новое поле с выражением НомерСтроки() и включите его в выбранные поля настроек отчёта. Нумерация появится при выводе. Учтите, что в отчётах с группировками нумерация может вестись в пределах каждой группы — проверьте поведение на своих данных.
Как сделать сквозную нумерацию при группировках в запросе?
В самом запросе — никак, это ограничение платформы. Выгрузите результат с детальными строками в таблицу значений и пронумеруйте её целиком одним счётчиком: группировки при этом сохранятся в данных, а номера будут сквозными. В СКД сквозную нумерацию даёт вычисляемое поле НомерСтроки(), размещённое на уровне детальных записей.
Нужен ли номер строки в динамическом списке формы?
Обычно нет: динамический список дочитывает данные порциями, и стабильный номер строки в нём обеспечить нельзя. Если номер действительно нужен пользователю, замените динамический список таблицей значений с собственной колонкой номера, заполняемой программно. Учтите, что при этом теряется автоматическое обновление списка.
Что делать, если нумерация сбивается при повторном выполнении запроса?
Причина почти всегда в неоднозначной сортировке: несколько строк имеют одинаковые значения в полях УПОРЯДОЧИТЬ ПО, и платформа возвращает их в произвольном порядке. Добавьте в сортировку уникальное поле — ссылку или код — и нумерация станет стабильной. Если сбой происходит в СКД, проверьте также уровень группировки, на котором размещено вычисляемое поле.