Как обратиться к колонке таблицы значений: имя, индекс, перебор
Содержание
Чтобы обратиться к колонке таблицы значений по имени, пишут Таблица.Колонки.Контрагент или Таблица.Колонки["Контрагент"]. Это самый короткий способ, но у него есть ловушка: если колонки с таким именем в таблице нет, код прервётся с ошибкой.
Когда имя колонки заранее неизвестно или таблица собирается динамически, безопаснее метод Найти. Вызов Таблица.Колонки.Найти("Контрагент") вернёт объект колонки, если она есть, и Неопределено, если её нет, — без исключения. Ниже разберём все способы доступа к колонкам таблицы значений: прямой по имени, поиск через Найти, обращение по индексу и перебор всех полей, а также когда какой из них применять.
Что такое коллекция колонок таблицы значений
У любой таблицы значений есть свойство Колонки. Это отдельная коллекция типа КоллекцияКолонокТаблицыЗначений. Она хранит не данные строк, а описания полей: имя, заголовок, тип значения и ширину.
Каждый элемент коллекции — объект КолонкаТаблицыЗначений с полезными свойствами:
- 🏷
Имя— программное имя колонки (идентификатор, по которому к ней обращаются); - 📝
Заголовок— текст для отображения в форме; - 🔢
ТипЗначения— описание типов, которые можно хранить в колонке; - 📏
Ширина— ширина колонки при выводе.
Узнать число колонок помогает метод Количество(). Не путайте его с числом строк: Таблица.Колонки.Количество() возвращает количество полей, а Таблица.Количество() — количество строк. Это разные величины у одной и той же таблицы.
Всего = Таблица.Колонки.Количество();
Сообщить("В таблице колонок: " + Всего);
Коллекцию колонок можно менять независимо от данных: добавлять и удалять поля, переименовывать их, менять порядок. Именно поэтому перед изменением структуры удобно сначала найти нужную колонку и убедиться, что она существует.
К самой коллекции можно обратиться двумя способами — по имени и по порядковому номеру. Отсюда и растут разные приёмы поиска колонки.
Прямой доступ по имени — быстро, но без страховки
Если вы точно знаете, что колонка существует, обращайтесь к ней напрямую. Работают две формы записи, они равнозначны:
// Через точку — имя как идентификатор
Колонка = Таблица.Колонки.Контрагент;
// Через оператор [] — имя строкой
Колонка = Таблица.Колонки["Контрагент"];
Вторая форма удобна, когда имя лежит в переменной:
ИмяПоля = "Контрагент";
Колонка = Таблица.Колонки[ИмяПоля];
Главное ограничение этого способа: если колонки с таким именем нет, выполнение прервётся с ошибкой. Для фиксированной таблицы, которую вы сами создали пару строк выше, это не проблема — имена под контролем. Но для таблицы, пришедшей из выборки запроса с условными полями, из внешнего источника или сформированной динамически, прямое обращение опасно.
Прямой доступ по имени не подходит, когда имя колонки приходит извне (из настроек, параметра процедуры, реквизита формы). Там колонки может не оказаться, и один неожиданный вызов обрушит обработку.
Безопасная проверка колонки методом Найти
Метод Найти коллекции колонок решает ровно эту задачу — проверить, есть ли колонка, и не упасть, если её нет. Он принимает имя строкой и возвращает либо объект колонки, либо Неопределено:
Колонка = Таблица.Колонки.Найти("Контрагент");
Если Колонка = Неопределено Тогда
Сообщить("Колонки «Контрагент» в таблице нет");
Иначе
Сообщить("Тип колонки: " + Строка(Колонка.ТипЗначения));
КонецЕсли;
Сравнивать результат нужно именно с Неопределено, а не с пустой строкой или нулём — это частая ошибка новичков.
Типовой сценарий — прочитать значения поля только в том случае, если колонка в таблице есть:
ИмяПоля = "Сумма";
Если Таблица.Колонки.Найти(ИмяПоля) <> Неопределено Тогда
Для Каждого Строка Из Таблица Цикл
Значение = Строка[ИмяПоля];
// здесь обрабатываем Значение
КонецЦикла;
КонецЕсли;
Не путайте Таблица.Колонки.Найти(…) и Таблица.Найти(…). Первый ищет колонку по имени в коллекции колонок. Второй ищет строку по значению в самой таблице и возвращает строку таблицы значений либо Неопределено. Это разные методы разных объектов.
Обращение к колонке по порядковому номеру
Иногда имя неважно, а нужна колонка по позиции — например, первая или последняя. Коллекция поддерживает индексацию с нуля:
Первая = Таблица.Колонки[0];
Последняя = Таблица.Колонки[Таблица.Колонки.Количество() - 1];
То же самое делает метод Получить:
Колонка = Таблица.Колонки.Получить(0);
Обратная операция — узнать номер уже найденной колонки — у метода Индекс:
Найденная = Таблица.Колонки.Найти("Сумма");
Если Найденная <> Неопределено Тогда
Номер = Таблица.Колонки.Индекс(Найденная);
Сообщить("Колонка «Сумма» идёт под номером " + Номер);
КонецЕсли;
Обращение по индексу тоже не прощает ошибок: номер за границами коллекции вызовет исключение. Поэтому перед выходом за последний элемент проверяйте Количество().
Перебор всех колонок таблицы
Когда заранее неизвестно, какие поля есть в таблице, их перебирают циклом Для Каждого. Это универсальный способ: он работает с любой таблицей, даже если вы не знаете ни одного имени колонки.
Для Каждого Колонка Из Таблица.Колонки Цикл
Сообщить(Колонка.Имя + " — " + Строка(Колонка.ТипЗначения));
КонецЦикла;
Так удобно выгружать структуру незнакомой таблицы, строить список полей для формы отбора или переносить данные между таблицами с разным набором колонок.
Перебор пригодится и для поиска колонки по условию, которое нельзя выразить именем, — например, найти первое поле числового типа:
ЧисловаяКолонка = Неопределено;
Для Каждого Колонка Из Таблица.Колонки Цикл
Если Колонка.ТипЗначения.СодержитТип(Тип("Число")) Тогда
ЧисловаяКолонка = Колонка;
Прервать;
КонецЕсли;
КонецЦикла;
Для чтения значения конкретного поля в каждой строке у строки таблицы работают те же формы обращения, что и у колонок: по имени через точку, по имени строкой и по индексу.
Для Каждого Строка Из Таблица Цикл
ПоИмени = Строка.Сумма; // если колонка точно есть
ПоСтроке = Строка["Сумма"]; // имя в кавычках или в переменной
ПоНомеру = Строка[0]; // по индексу колонки
КонецЦикла;
Пример: перенос данных между таблицами с разными колонками
Классическая задача, где поиск колонки обязателен, — скопировать строки из одной таблицы значений в другую, когда наборы колонок совпадают не полностью. Прямое НоваяСтрока = Источник тут не сработает: лишние поля приёмника останутся пустыми, а недостающие вызовут ошибку.
Решение — для каждой колонки источника проверять Найти в приёмнике и переносить только то, что есть в обеих таблицах:
Для Каждого СтрокаИсточника Из Источник Цикл
НоваяСтрока = Приёмник.Добавить();
Для Каждого Колонка Из Источник.Колонки Цикл
Если Приёмник.Колонки.Найти(Колонка.Имя) <> Неопределено Тогда
НоваяСтрока[Колонка.Имя] = СтрокаИсточника[Колонка.Имя];
КонецЕсли;
КонецЦикла;
КонецЦикла;
Такой перенос не зависит от порядка колонок и не падает, если в источнике появилось новое поле. Именно сочетание перебора колонок и метода Найти делает код устойчивым к изменениям структуры таблиц.
Если же наборы колонок заведомо одинаковы, копировать таблицу целиком проще методом Скопировать: Копия = Исходная.Скопировать(). Поиск колонок там не нужен — структура переносится вместе с данными.
Какой способ быстрее и когда его применять
Разница в скорости заметна только на больших объёмах — десятки тысяч строк и повторный доступ в цикле. Общая логика такая:
| Способ | Когда применять | Поведение при отсутствии |
|---|---|---|
Колонки.Имя / Колонки["Имя"] | имя фиксированное, колонка точно есть | ошибка |
Колонки.Найти("Имя") | имя из переменной, колонка может отсутствовать | возвращает Неопределено |
Колонки[Индекс] / Получить() | известен порядковый номер | ошибка при выходе за границы |
Цикл Для Каждого | нужно обойти все колонки или искать по условию | обходит фактические колонки |
Главный приём оптимизации — не разрешать имя колонки повторно внутри большого цикла по строкам. Если в цикле на сто тысяч строк каждый раз писать Строка["Сумма"], 1С каждый раз сопоставляет строковое имя с колонкой. Дешевле один раз получить индекс колонки до цикла и обращаться по нему:
ИндексСуммы = Таблица.Колонки.Индекс(Таблица.Колонки.Найти("Сумма"));
Для Каждого Строка Из Таблица Цикл
Итого = Итого + Строка[ИндексСуммы];
КонецЦикла;
На типичных обработках (несколько тысяч строк) разница незаметна, и ради читаемости обычно оставляют обращение по имени. Оптимизация по индексу оправдана на тяжёлых пакетных операциях.
Таблица.Колонки.Имя или Таблица.Колонки["Имя"]. Самый короткий и читаемый вариант.Таблица.Колонки.Найти("Имя") с проверкой результата на Неопределено. Исключения не будет.Для Каждого Колонка Из Таблица.Колонки Цикл. Работает с любой таблицей.Таблица.Колонки[Номер] или Получить(Номер), с проверкой Количество().Поиск колонки перед добавлением и выгрузкой значений
Чаще всего Найти используют не ради самой колонки, а чтобы безопасно выполнить следующую операцию. Два таких сценария встречаются почти в каждой обработке.
Добавить колонку, только если её ещё нет. Повторный Добавить с тем же именем вызовет ошибку, поэтому перед добавлением проверяют существование. Получается идемпотентный код — его можно выполнять сколько угодно раз без последствий:
Если Таблица.Колонки.Найти("Остаток") = Неопределено Тогда
Таблица.Колонки.Добавить("Остаток", Новый ОписаниеТипов("Число"), "Остаток");
КонецЕсли;
Метод Добавить принимает имя, описание типов, заголовок и ширину. Описание типов необязательно: без него колонка примет значения любого типа. Такой приём незаменим, когда одна процедура дополняет таблицу, собранную в разных местах, и не знает наверняка, какие поля в ней уже есть.
Выгрузить все значения колонки в массив. Когда колонка найдена и нужны все её значения разом, не пишите цикл вручную — есть метод ВыгрузитьКолонку. Он принимает имя, индекс или объект колонки и возвращает массив:
Если Таблица.Колонки.Найти("Контрагент") <> Неопределено Тогда
Контрагенты = Таблица.ВыгрузитьКолонку("Контрагент");
// Контрагенты — массив значений из всех строк
КонецЕсли;
Полученный массив удобно свернуть в уникальный список, передать в запрос как параметр или сложить. Обратная операция — ЗагрузитьКолонку(Массив, "Имя") — записывает значения из массива обратно в колонку по именам, индексу или объекту.
Если нужно просто просуммировать числовую колонку, короче метод Итог: Таблица.Итог("Сумма"). Он тоже принимает имя колонки и возвращает число, минуя ручной перебор строк.
Частые ошибки при работе с колонками
Большинство падений кода вокруг колонок таблицы значений сводится к нескольким типовым промахам.
- 🚫 Прямое обращение без проверки.
Таблица.Колонки.Полена таблице, где поля может не быть. Решение —Найтис проверкой наНеопределено. - 🔄 Путаница
Колонки.НайтииНайтитаблицы. Первый ищет колонку по имени, второй — строку по значению. Результаты и смысл разные. - ❌ Сравнение результата
Найтине с тем значением. ПисатьЕсли Колонка = "" Тогданеверно — метод возвращаетНеопределено, а не пустую строку. - 🔢 Выход за границы по индексу.
Колонки[Количество()]вместоКоличество() - 1. Нумерация идёт с нуля. - 🐌 Разрешение имени в тяжёлом цикле. Сотни тысяч обращений
Строка["Поле"]вместо заранее полученного индекса — лишняя нагрузка на больших данных.
Если в таблице встречаются поля с одинаковым смыслом, но разными именами в разных источниках (например, Партнёр и Контрагент), не плодите ветки Если. Соберите список возможных имён и пройдите его в цикле через Найти — первая найденная колонка и будет искомой.
Частые вопросы
Чем `Колонки.Найти()` отличается от `Найти()` самой таблицы?
Таблица.Колонки.Найти("Имя") ищет колонку в коллекции колонок и возвращает объект колонки либо Неопределено. Таблица.Найти(Значение) ищет строку по значению во всех колонках (или в указанных) и возвращает строку таблицы либо Неопределено. Это разные методы разных объектов.Что вернёт `Найти`, если колонки с таким именем нет?
Неопределено. Исключение не возникает, поэтому результат можно спокойно проверить условием Если Колонка = Неопределено Тогда.Как получить колонку по порядковому номеру, а не по имени?
Таблица.Колонки[0] или метод Таблица.Колонки.Получить(0). Последнюю колонку берут как Колонки[Колонки.Количество() - 1].Как узнать тип значения и заголовок найденной колонки?
ТипЗначения, Заголовок, Имя и Ширина. Например, Колонка.ТипЗначения.СодержитТип(Тип("Число")) проверит, допускает ли колонка числа.Как безопасно прочитать значение поля, если его имя хранится в переменной?
Если Таблица.Колонки.Найти(ИмяПоля) <> Неопределено Тогда. Затем читайте значение в строке через оператор []: Значение = Строка[ИмяПоля].