Как оставить или выбрать первые 100 строк в Таблице Значений в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Почему не работает удаление строк в прямом цикле

Рассмотрим типичный пример кода, в котором предпринимается попытка перебрать таблицу и удалить элементы, начиная с сотой строки:


Данные1 = Данные.Скопировать(); 

Сч = 0;
Пока Сч < Данные1.Количество()-1 Цикл
    СтрТаб = Данные1.Получить(Сч);
    Если Сч >= 100 Тогда
        Данные1.Удалить(СтрТаб);
    Иначе
        Сч = Сч + 1;
    КонецЕсли;
КонецЦикла;

В этом алгоритме кроются сразу три критические проблемы:

  1. Сдвиг индексов элементов: При вызове метода Удалить() все последующие строки таблицы значений сдвигаются на одну позицию вверх (к началу). Из-за этого текущий индекс начинает указывать на другую строку, а часть элементов просто пропускается.
  2. Динамическое изменение размера таблицы: Условие Данные1.Количество() пересчитывается на каждой итерации. Удаление элементов постоянно уменьшает общую длину таблицы, из-за чего цикл работает некорректно.
  3. Отсутствие проверки на границы коллекции: Если в исходной таблице окажется меньше 100 строк, прямой цикл с жестко заданными индексами вызовет ошибку «Выход за границы коллекции». Верхний предел цикла всегда необходимо ограничивать с помощью функции Мин().

Способ 1. Удаление лишних строк с конца таблицы (модификация по месту)

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

Разберем пример реализации данного подхода:


Пока ИсходнаяТЗ.Количество() > 100 Цикл
    ИсходнаяТЗ.Удалить(ИсходнаяТЗ.Количество() - 1);
КонецЦикла;

Этот метод работает по принципу: пока общее количество строк превышает 100, удаляется строка с последним индексом Количество() - 1. Операция выполнятся быстро и не требует выделения памяти под новые таблицы или массивы.

Способ 2. Скопировать структуру и заполнить первые N строк

Часто требуется сохранить исходную таблицу неизменной и сформировать новую таблицу значений, содержащую первые 100 строк. Чтобы не описывать колонки вручную, можно скопировать структуру с помощью метода СкопироватьКолонки(), после чего в цикле перенести данные с помощью функции ЗаполнитьЗначенияСвойств().

Посмотрим на пример кода с защитой от выхода за границы массива:


НоваяТЗ = ИсходнаяТЗ.СкопироватьКолонки();
Предел = Мин(100, ИсходнаяТЗ.Количество()) - 1;

Для Индекс = 0 По Предел Цикл
    НоваяСтрока = НоваяТЗ.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, ИсходнаяТЗ[Индекс]);
КонецЦикла;

Обратим внимание на вычисление переменной Предел. Конструкция Мин(100, ИсходнаяТЗ.Количество()) - 1 гарантирует, что если в исходной таблице окажется, например, всего 50 строк, цикл безопасно отработает от 0 до 49 и не вызовет исключение.

Способ 3. Использование массива строк и метода Скопировать()

Метод Скопировать() объекта ТаблицаЗначений позволяет передать в качестве параметра массив конкретных строк, которые необходимо скопировать в новую таблицу. Это лаконичный способ, полностью сохраняющий структуру и типы колонок.

Проанализируем этот вариант:


МассивСтрок = Новый Массив;
Предел = Мин(100, ИсходнаяТЗ.Количество()) - 1;

Для Индекс = 0 По Предел Цикл
    МассивСтрок.Добавить(ИсходнаяТЗ[Индекс]);
КонецЦикла;

НоваяТЗ = ИсходнаяТЗ.Скопировать(МассивСтрок);

В данном случае мы сначала заполняем МассивСтрок ссылками на первые 100 строк таблицы, а затем вызываем метод Скопировать(), передавая этот массив. Платформа 1С автоматически создаст новую таблицу значений и заполнит её указанными строками.

Способ 4. Выборка первых строк через Запрос

Получить первые 100 строк можно и с помощью запроса, передав таблицу значений в качестве параметра. Однако здесь есть важные особенности платформы 1С, о которых необходимо помнить.

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

Рассмотрим пример правильного написания запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 100
    |   МояТЗ.Колонка1 КАК Колонка1,
    |   МояТЗ.Колонка2 КАК Колонка2
    |ИЗ
    |   &МояТЗ КАК МояТЗ
    |УПОРЯДОЧИТЬ ПО
    |   МояТЗ.НомерСтроки";

Запрос.УстановитьПараметр("МояТЗ", ИсходнаяТЗ);
ТЗ100 = Запрос.Выполнить().Выгрузить();

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

Итоги

Мы рассмотрели четыре основных подхода к получению первых N строк из таблицы значений в 1С. Для модификации существующей таблицы по месту без создания новых объектов оптимально использовать обратный цикл с удалением элементов с конца. Если требуется сформировать новую таблицу значений, наиболее удобными и безопасными являются варианты с заполнением свойств в цикле или копированием через массив строк с проверкой количества элементов через Мин().

← На главную