Вопрос нумерации строк в языке запросов 1С долгое время оставался одним из самых обсуждаемых. Разработчики часто сталкиваются с необходимостью получить порядковый номер записи непосредственно в выборке, будь то для вывода в отчет, реализации сложной логики во временных таблицах или формирования уникальных индексов, а также при выполнении запросов через COM-подключение. Мы проведем быстрый анализ данных и проанализируем основные подходы, разберем их преимущества и недостатки, а также выясним, какие инструменты, включая управляемую консоль запросов (удобнее через профессиональная консоль запросов и СКД), предоставляет современная платформа 1С:Предприятие 8.
Начиная с версии платформы 8.3.13, в языке запросов появилась долгожданная встроенная функция АВТОНОМЕРЗАПИСИ(). Это наиболее производительный и правильный метод нумерации, если ваша конфигурация работает на актуальной платформе — для проверки нагрузки пригодится инструмент анализа производительности и планов запросов. Разберем, как она функционирует.
Функция генерирует последовательные целые числа, начиная с единицы. Рассмотрим простейший пример использования:
ВЫБРАТЬ
АВТОНОМЕРЗАПИСИ() КАК НомерСтроки,
Номенклатура.Наименование КАК Товар,
Номенклатура.Код КАК Код
ИЗ
Справочник.Номенклатура КАК Номенклатура
УПОРЯДОЧИТЬ ПО
Наименование
Используя процессор схемы запроса, проанализируем важные нюансы работы этой функции, которые помогут избежать ошибок при разработке:
АВТОНОМЕРЗАПИСИ() напрямую зависит от порядка, указанного в секции УПОРЯДОЧИТЬ ПО. Если сортировка не задана, номера могут распределяться произвольно, что часто недопустимо.ГДЕ, СГРУППИРОВАТЬ ПО или ИМЕЮЩИЕ. Она предназначена исключительно для формирования результирующей колонки выборки.Если ваша задача — вывести нумерацию строк в отчете, то изменять сам текст запроса зачастую не требуется. Система компоновки данных предоставляет встроенные механизмы для этой цели. Выясним, как это реализовать наиболее эффективно.
В СКД существуют специальные системные поля, которые доступны в настройках отчета:
НомерВПорядке — возвращает сквозной номер строки в текущем уровне группировки.НомерПоСерии — аналогичное поле, часто используемое для нумерации детальных записей.Рассмотрим пошагово, как добавить нумерацию в отчет:
НомерВПорядке в список выбранных.Этот метод является самым производительным, так как нумерация происходит на этапе вывода данных, не нагружая сервер СУБД сложными вычислениями в самом запросе. Для отладки запросов и схем компоновки данных можно использовать инженерную консоль запросов с поддержкой отчетов СКД.
Посмотрим на классический, но «тяжелый» способ, который использовался программистами до появления платформы 8.3.13. Он основан на подсчете количества записей, которые «меньше или равны» текущей записи по определенному критерию (например, по дате или коду).
Проанализируем пример запроса для нумерации документов:
ВЫБРАТЬ
ПоступлениеТоваровУслуг.Ссылка КАК Ссылка,
КОЛИЧЕСТВО(ПоступлениеТоваровУслуг_1.Ссылка) КАК ПорядковыйНомер
ИЗ
Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг
ВНУТРЕННЕЕ СОЕДИНЕНИЕ
Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг_1
ПО
ПоступлениеТоваровУслуг.Дата >= ПоступлениеТоваровУслуг_1.Дата
СГРУППИРОВАТЬ ПО
ПоступлениеТоваровУслуг.Ссылка
УПОРЯДОЧИТЬ ПО
ПорядковыйНомер
Критически важно: Этот метод имеет квадратичную сложность. Разберем причину: для каждой из N строк система должна выполнить сравнение с другими строками. Если в таблице 100 записей — это 10 000 сравнений. Если 10 000 записей — это уже 100 000 000 операций. Мы крайне не рекомендуем использовать этот подход на больших объемах данных, так как это приведет к зависанию системы или переполнению памяти сервера.
Иногда требуется пронумеровать данные, которые передаются в запрос извне, например, из ТаблицыЗначений. В этом случае самым надежным способом будет добавление колонки с номером в саму таблицу значений перед ее передачей в запрос.
Рассмотрим пример кода на языке 1С:
// Добавляем колонку в ТЗ
ТЗДанные.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10)));
// Заполняем номера
Для Счетчик = 0 По ТЗДанные.Количество() - 1 Цикл
ТЗДанные[Счетчик].НомерСтроки = Счетчик + 1;
КонецЦикла;
// Передаем ТЗ в запрос
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ВТ КАК ВТ";
Запрос.УстановитьПараметр("ВТ", ТЗДанные);
Этот метод гарантирует стабильность и предсказуемость результата. Мы точно знаем, какой номер соответствует какой строке, и можем использовать это поле для последующих соединений с другими таблицами в рамках одного сложного запроса.
В процессе обсуждения нумерации часто возникает вопрос о представлении номера в виде строки или склейке его с другими данными. Напомним, что начиная с версии 8.3.6, язык запросов поддерживает оператор + для строк ограниченной длины.
Если нам нужно собрать строку вида «Запись №5», мы можем использовать конструкцию:
ВЫБРАТЬ
"Запись №" + ПРЕДСТАВЛЕНИЕ(АВТОНОМЕРЗАПИСИ()) КАК Пояснение
ИЗ
Справочник.Номенклатура
Однако помните, что при работе со строками неограниченной длины их необходимо предварительно приводить к фиксированной длине с помощью функции ПОДСТРОКА().
Подводя итог, выберем оптимальную стратегию для разных ситуаций:
АВТОНОМЕРЗАПИСИ().НомерВПорядке.ТаблицуЗначений программно перед вызовом запроса.Выяснив все технические детали, мы видим, что 1С прошла путь от полного отсутствия нумерации в запросах до внедрения эффективных встроенных функций. Правильный выбор метода позволит вам писать производительный код и избегать типичных ошибок начинающих разработчиков.