Как перейти к конкретной строке в выборке запроса 1С?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

При работе с результатами запросов в среде «1С:Предприятие» начинающие разработчики часто сталкиваются с проблемой: как быстро «прыгнуть» на определенную строку (например, на сотую или тысячную), не перебирая все предыдущие записи. Типичная ошибка заключается в попытке использовать метод Получить() непосредственно у объекта выборки, что приводит к исключению «Значение индекса выходит за границы диапазона».

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

Разбор основной ошибки: Выборка vs Таблица значений

Рассмотрим ситуацию, с которой столкнулся автор темы. При выполнении кода ВыборкаДетальныеЗаписи.Получить(100) система выдает ошибку, даже если в результате запроса тысячи строк. Выясним причину: у объекта ВыборкаИзРезультатаЗапроса метод Получить(Индекс) предназначен для получения значения поля (колонки) текущей записи, а не самой строки. Если в вашем запросе выбрано 4 поля, то допустимые индексы — от 0 до 3. Попытка обратиться к индексу 100 воспринимается системой как обращение к 101-й колонке, которой не существует.

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

Решение №1: Выгрузка в таблицу значений

Самый простой и интуитивно понятный способ — преобразовать динамическую выборку в статичную таблицу значений. Это позволяет обращаться к любой строке по индексу, используя квадратные скобки.

Рассмотрим пример реализации:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ИнвентарныеНомераОС.Ссылка КАК Ссылка,
    |   ИнвентарныеНомераОС.Код КАК Код
    |ИЗ
    |   Справочник.ИнвентарныеНомераОС КАК ИнвентарныеНомераОС";

Результат = Запрос.Выполнить();

// Вместо Результат.Выбрать() используем Выгрузить()
ТаблицаРезультатов = Результат.Выгрузить();

// Теперь мы можем обратиться к 100-й строке (индекс 99)
Если ТаблицаРезультатов.Количество() >= 100 Тогда
    НужнаяСтрока = ТаблицаРезультатов[99];
    Сообщить("Код 100-й записи: " + НужнаяСтрока.Код);
КонецЕсли;

Важное замечание: Метод Выгрузить() копирует все данные из временного хранилища в оперативную память сервера. Если запрос возвращает сотни тысяч строк, это может привести к избыточному потреблению ресурсов. Используйте этот метод только для небольших или средних объемов данных.

Решение №2: Последовательный перебор выборки

Если нам важно сохранить экономию памяти, мы можем использовать стандартный объект ВыборкаИзРезультатаЗапроса. Поскольку выборка — это «курсор», который двигается только вперед, нам придется пропустить ненужные строки с помощью цикла.

Разберем, как это сделать правильно:


Выборка = Результат.Выбрать();
НомерНужнойСтроки = 100;
ТекущийНомер = 0;

Пока Выборка.Следующий() Цикл
    ТекущийНомер = ТекущийНомер + 1;
    Если ТекущийНомер = НомерНужнойСтроки Тогда
        // Мы встали на нужную позицию
        Сообщить("Мы на 100-й строке: " + Выборка.ИнвНомер);
        Прервать; 
    КонецЕсли;
КонецЦикла;

Этот метод работает медленнее, чем прямое обращение по индексу в таблице, но он практически не потребляет оперативную память, так как данные читаются порциями.

Решение №3: Использование метода НайтиСледующий()

Если целью является не просто «строка номер 100», а строка с определенным значением (например, конкретным инвентарным номером), то оптимально использовать метод НайтиСледующий(). Посмотрим на пример:


ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("Код", "000000123");

Выборка = Результат.Выбрать();
Если Выборка.НайтиСледующий(ПараметрыПоиска) Тогда
    // Выборка автоматически позиционируется на найденной строке
    Сообщить("Запись найдена!");
КонецЕсли;

Современные методы (Платформа 8.3.20+)

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

Зачем это нужно? Мы можем обернуть основной запрос во вложенный и наложить условие ГДЕ на поле с номером строки. Это самый производительный способ, так как сервер 1С получит от SQL-сервера только одну конкретную строку, а не всю выборку.

Рекомендации по выбору метода

  1. Малые объемы данных: Используйте Выгрузить() и обращение через квадратные скобки Таблица[Индекс]. Это дает самый чистый и понятный код.
  2. Большие объемы данных: Используйте цикл с методом Следующий() или постраничную выборку через конструкцию ВЫБРАТЬ ПЕРВЫЕ... в самом тексте запроса.
  3. Повторный обход: Если вы уже просмотрели выборку и вам нужно вернуться в начало, используйте метод Выборка.Сбросить(). Это вернет указатель в позицию «перед первой строкой», и вы сможете начать отсчет заново без повторного обращения к базе данных.
  4. Поиск конкретики: Всегда отдавайте предпочтение методу НайтиСледующий(), если у вас есть уникальный идентификатор строки.

Таким образом, выбор метода позиционирования напрямую зависит от контекста задачи. Понимание разницы между получением значения колонки и переходом к строке поможет вам избежать досадных ошибок и писать более оптимизированный код.

← На главную