Как получить первую строку из таблицы значений в 1С и безопасно извлечь ее данные?

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

Введение

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

Базовый метод получения строки по индексу

Для начала проанализируем базовый синтаксис работы с коллекцией строк таблицы значений. Каждый элемент в таблице значений имеет свой уникальный порядковый номер — индекс. Важно помнить фундаментальное правило платформы «1С:Предприятие»: индексация строк в таблице значений всегда начинается с нуля (0). Соответственно, первая строка таблицы имеет индекс 0, вторая — индекс 1, третья — индекс 2 и так далее.

Обратиться к строке по индексу можно двумя равноценными способами:

  1. Используя квадратные скобки: МояТЗ[0]
  2. Используя явный метод: МояТЗ.Получить(0)

Оба этих варианта работают с одинаковой скоростью и возвращают объект типа СтрокаТаблицыЗначений. Рассмотрим простой пример, когда нам нужно получить значение из колонки НужныйРеквизит первой строки таблицы:

ОснованиеПлатежей = МояТЗ[0].НужныйРеквизит;

Казалось бы, решение найдено и задача выполнена. Однако в реальной практике такой простой код таит в себе серьезную опасность. Если таблица значений окажется пустой (то есть не будет содержать ни одной строки), выполнение этой строки кода немедленно вызовет критическую ошибку выполнения (исключение) с сообщением «Индекс находится за границами диапазона». Чтобы этого не произошло, всегда необходимо выполнять проверку.

Обеспечение безопасности: проверка количества строк

Разберем по шагам, как защитить наш код от непредвиденного падения. Перед тем как обращаться к какому-либо элементу коллекции по его индексу, мы обязаны убедиться, что в коллекции есть хотя бы один элемент. Для этого используется метод Количество(). Посмотрим на правильную реализацию этого алгоритма:


Если МояТЗ.Количество() > 0 Тогда
    ОснованиеПлатежей = МояТЗ[0].НужныйРеквизит;
Иначе
    ОснованиеПлатежей = ""; // Или другое дефолтное значение
КонецЕсли;

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

Глубокая проверка: тип данных и наличие колонок

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

Для решения первой проблемы мы применим проверку типа данных с помощью функции ТипЗнч(). Для решения второй проблемы мы обратимся к коллекции колонок таблицы значений Колонки и используем метод Найти(). Объединим эти проверки в единую надежную конструкцию:


Если ТипЗнч(МояТЗ) = Тип("ТаблицаЗначений") И МояТЗ.Количество() > 0 Тогда
    // Проверяем, существует ли нужная колонка в структуре таблицы
    Если МояТЗ.Колонки.Найти("НужныйРеквизит") <> Неопределено Тогда
        ОснованиеПлатежей = МояТЗ[0].НужныйРеквизит;
    Иначе
        ОснованиеПлатежей = "";
        // Здесь можно зафиксировать предупреждение в журнале регистрации
    КонецЕсли;
Иначе
    ОснованиеПлатежей = "";
КонецЕсли;

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

Важность предварительной сортировки данных

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

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


МояТЗ.Сортировать("ДатаДокумента Возр");
Если МояТЗ.Количество() > 0 Тогда
    ОснованиеПлатежей = МояТЗ[0].НужныйРеквизит;
КонецЕсли;

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


ОбъектСравнения = Новый СравнениеЗначений;
МояТЗ.Сортировать("ДоговорКонтрагента", ОбъектСравнения);

Этот прием позволяет значительно ускорить сортировку больших объемов данных в оперативной памяти.

Контекст исполнения кода: Клиент и Сервер

Проанализируем еще одну архитектурную особенность платформы. Объект ТаблицаЗначений является исключительно серверным объектом. Он недоступен на Тонком клиенте. Если ваша процедура выполняется в контексте управляемой формы на клиенте (например, при нажатии кнопки пользователем), прямая работа с таблицей значений вызовет ошибку компиляции.

На клиенте разработчик обычно взаимодействует с объектом типа ДанныеФормыКоллекция (который визуализируется на форме как таблица). Синтаксис работы с ним очень похож, и мы также можем получить первую строку по индексу 0:


Если Объект.ТабличнаяЧастьДокумента.Количество() > 0 Тогда
    ПерваяСтрокаКлиент = Объект.ТабличнаяЧастьДокумента[0];
    ОснованиеПлатежей = ПерваяСтрокаКлиент.НужныйРеквизит;
КонецЕсли;

Тем не менее, передавать полноценную таблицу значений с сервера на клиент напрямую нельзя — для этого требуется предварительная конвертация данных во вспомогательные структуры (например, в массив структур) или использование временного хранилища.

Альтернативный вариант: Ограничение на уровне запроса

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

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


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

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

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

Заключение

Мы детально рассмотрели процесс извлечения первой строки из таблицы значений в 1С. Подведем итоги совместной работы:

  1. Первая строка таблицы всегда имеет индекс 0.
  2. Перед обращением к строке обязательно проверяйте коллекцию на пустоту методом Количество() > 0.
  3. Для промышленного кода используйте глубокую проверку типов и проверку наличия колонок методом Колонки.Найти().
  4. Не забывайте о сортировке таблицы значений методом Сортировать() с использованием объекта СравнениеЗначений для оптимизации по ссылочным полям.
  5. Если данные берутся из базы данных, стремитесь переносить логику ограничения выборки непосредственно в запрос через оператор ВЫБРАТЬ ПЕРВЫЕ 1.

Соблюдение этих простых, но крайне важных правил позволит вам создавать надежные, быстрые и легко поддерживаемые решения на платформе «1С:Предприятие».

← На главную