К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как обойти колонки таблицы значений в 1С

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

Таблица значений в 1С — один из самых востребованных объектов: в неё выгружаются результаты запросов, в ней готовятся данные для отчётов, обменов и печатных форм. При этом обход колонок нужен реже, чем обход строк, поэтому у начинающих разработчиков он вызывает вопросы: колонки нельзя перебрать так же наглядно, как строки, и синтаксис у коллекции колонок свой.

На практике обход колонок требуется в типовых сценариях: динамическое формирование колонок по структуре другой таблицы, универсальная выгрузка в Excel или CSV, свёртка таблицы с неизвестным заранее составом колонок, сравнение двух таблиц, преобразование типов значений в колонке. Во всех этих задачах код не должен «знать» имена колонок заранее — он получает их из коллекции Таблица.Колонки.

Ниже разобраны рабочие способы обхода колонок, доступ к значениям по имени и индексу, типичные ошибки и ограничения платформы. Все примеры написаны на встроенном языке 1С и работают как на сервере, так и на клиенте, если не указано иное.

Коллекция колонок: что нужно знать перед обходом

Колонки таблицы значений хранятся в свойстве Колонки — это объект типа «КоллекцияКолонокТаблицыЗначений». Каждый элемент коллекции — объект «КолонкаТаблицыЗначений» со свойствами Имя, ТипЗначения, Заголовок, Ширина. Именно эти свойства используются внутри цикла обхода.

Важное отличие от строк: колонки нельзя удалить или добавить «на лету» внутри цикла обхода той же коллекции — изменение состава коллекции во время итерации приводит к ошибке или к пропуску элементов. Если нужно удалить часть колонок, сначала соберите их имена в отдельный массив, а удаляйте уже после завершения цикла.

Количество колонок доступно через ТЗ.Колонки.Количество(), а обращение по индексу — ТЗ.Колонки[0]. Индексация начинается с нуля, как и во всех коллекциях платформы.

Базовый обход колонок циклом «Для Каждого»

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

Для Каждого Колонка Из ТЗ.Колонки Цикл

Сообщить("Колонка: " + Колонка.Имя

+ ", тип: " + Колонка.ТипЗначения

+ ", заголовок: " + Колонка.Заголовок);

КонецЦикла;

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

Альтернатива — обход по индексу через цикл Для. Он нужен, когда требуется номер колонки, например для записи в конкретную ячейку листа Excel:

Для Индекс = 0 По ТЗ.Колонки.Количество() - 1 Цикл

Колонка = ТЗ.Колонки[Индекс];

// Индекс + 1 — номер колонки в Excel

КонецЦикла;

Обход колонок вместе со строками: доступ к значениям ячеек

Чаще всего обход колонок вложен в обход строк: внешний цикл перебирает строки, внутренний — колонки, либо наоборот. Значение ячейки получают двумя способами: по имени колонки Строка[Колонка.Имя] или по индексу Строка[ИндексКолонки].

Для Каждого Строка Из ТЗ Цикл

Для Каждого Колонка Из ТЗ.Колонки Цикл

Значение = Строка[Колонка.Имя];

// обработка значения

КонецЦикла;

КонецЦикла;

Обращение по имени через квадратные скобки — универсальный приём, когда имена колонок неизвестны на момент написания кода. Если имя известно, предпочтительнее точечное обращение Строка.Сумма — оно читаемее и позволяет синтакс-помощнику контролировать код.

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

Универсальная выгрузка таблицы в CSV
  1. 1
    Обойдите колонки циклом «Для Каждого» и сформируйте строку заголовков через разделитель
  2. 2
    Откройте цикл по строкам таблицы
  3. 3
    Внутри цикла по строкам обойдите колонки и получите значения через Строка[Колонка.Имя]
  4. 4
    Преобразуйте значения в строку функцией XMLСтрока() или форматированием
  5. 5
    Запишите полученные строки в текстовый файл и проверьте результат, открыв файл в редакторе

Поиск и проверка существования колонки

Когда нужна не итерация, а конкретная колонка, используйте метод Найти коллекции колонок. Он возвращает объект колонки или Неопределено, если колонки с таким именем нет. Это стандартный способ защититься от ошибки «Поле не найдено» при работе с таблицами переменного состава.

КолонкаСумма = ТЗ.Колонки.Найти("Сумма");

Если КолонкаСумма = Неопределено Тогда

ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));

КонецЕсли;

Поиск по имени регистронезависим: Найти("Сумма") и Найти("СУММА") вернут одну и ту же колонку. Учитывайте это при сравнении имён вручную — прямое сравнение строк «Сумма = сумма» даст «Ложь», хотя для платформы это одна колонка.

Для проверки сразу нескольких обязательных колонок удобно обойти массив требуемых имён и для каждого вызвать Найти. Такой приём часто применяют в функциях-приёмниках таблиц извне — из запроса, файла или другой информационной базы.

bsl
Функция ЕстьВсеКолонки(ТЗ, ИменаКолонок)
    Для Каждого Имя Из ИменаКолонок Цикл
        Если ТЗ.Колонки.Найти(Имя) = Неопределено Тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЦикла;
    Возврат Истина;
КонецФункции

Динамическое добавление и копирование колонок

Обход колонок одной таблицы часто используют, чтобы построить другую таблицу с такой же или изменённой структурой. Метод ТЗ.Колонки.Добавить(Имя, ТипЗначения, Заголовок, Ширина) принимает описание типов, которое можно взять из исходной колонки:

НоваяТЗ = Новый ТаблицаЗначений;

Для Каждого Колонка Из ИсходнаяТЗ.Колонки Цикл

НоваяТЗ.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения, Колонка.Заголовок);

КонецЦикла;

Если нужна точная копия структуры без данных, проще вызвать ИсходнаяТЗ.СкопироватьКолонки() — метод вернёт новую таблицу с идентичным набором колонок. Ручной обход оправдан, когда структуру нужно изменить: пропустить часть колонок, переименовать их или расширить тип.

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

Операции над колонками: свёртка, итоги, изменение типа

Метод Свернуть требует строковых списков имён колонок: первый параметр — колонки группировки, второй — суммируемые колонки. Если состав формируется динамически, соберите эти списки обходом колонок с фильтром по типу:

СписокСумм = "";

Для Каждого Колонка Из ТЗ.Колонки Цикл

Если Колонка.ТипЗначения.СодержитТип(Тип("Число")) Тогда

СписокСумм = СписокСумм + ?(СписокСумм = "", "", ",") + Колонка.Имя;

КонецЕсли;

КонецЦикла;

Аналогично работает Итог(ИмяКолонки) — он принимает имя строкой, поэтому легко встраивается в цикл обхода. Для подсчёта итогов по всем числовым колонкам достаточно одного прохода по коллекции колонок без обхода строк — платформа посчитает итог сама.

Изменить тип существующей колонки напрямую нельзя: свойство ТипЗначения доступно только для чтения. Обходной путь — добавить новую колонку с нужным типом, перенести значения обходом строк и удалить старую колонку. Учтите, что удалённая колонка встаёт в конец невозможно — для сохранения порядка используйте метод Сдвинуть коллекции колонок.

Способы обхода колонок

Для Каждого по ТЗ.Колонки

Основной вариант: читаемый, безопасный, подходит для большинства задач. Не даёт номера колонки напрямую.

Цикл Для по индексу

Нужен, когда важна позиция колонки: выгрузка в Excel, сравнение по порядку. Код чуть громоздче.

Колонки.Найти(Имя)

Не обход, а точечный доступ. Используйте, когда состав колонок известен и нужно проверить наличие конкретной.

СкопироватьКолонки()

Заменяет ручной обход при точном копировании структуры. Не подходит, если структуру нужно изменить.

Типичные ошибки и ограничения платформы

Частая ошибка — попытка обратиться к значению через Строка.Колонка.Имя или похожей конструкцией. Точечное обращение работает только с литеральным именем колонки; для обращения по переменной используются квадратные скобки Строка[ИмяКолонки].

Вторая группа ошибок связана с изменением коллекции во время обхода: добавление колонки внутри цикла Для Каждого по колонкам приводит к непредсказуемой итерации. Решение — двухпроходная схема: сначала обход и сбор решений, затем модификация.

Третья группа — работа с деревом значений. У дерева тоже есть коллекция Колонки, и обход устроен так же, но строки имеют иерархию: для полного обхода данных нужна рекурсия по Строки каждой строки. Код, написанный для плоской таблицы, «не увидит» вложенные строки дерева.

Типичные ошибки
01
Обращение Строка.ИмяПеременной вместо Строка[ИмяПеременной] — платформа ищет колонку с именем переменной, а не с её значением
02
Добавление или удаление колонок внутри цикла обхода той же коллекции — итерация ломается, элементы пропускаются
03
Попытка присвоить Колонка.ТипЗначения новое значение — свойство только для чтения, нужна новая колонка
04
Индексация с единицы вместо нуля — ТЗ.Колонки[1] при одной колонке вызывает ошибку выхода за границы
05
Игнорирование регистронезависимости имён при ручном сравнении строк — ложные выводы об отсутствии колонки

Проверка результата и отладка обхода

После написания цикла убедитесь, что обход реально прошёл по всем колонкам: выведите в сообщение или журнал количество обработанных колонок и сравните с ТЗ.Колонки.Количество(). Расхождение — признак того, что коллекция менялась внутри цикла или фильтр отсёк лишнее.

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

Контрольные точки

Как проверить результат

Число обработанных колонок
Норма

Совпадает с ТЗ.Колонки.Количество()

Тревожный признак

Меньше — коллекция менялась в цикле или сработал фильтр

Значения после переноса в новую таблицу
Норма

Типы сохранены, числа и даты не превратились в строки

Тревожный признак

Все значения строковые — потерян ТипЗначения при добавлении колонок

Порядок колонок в результате
Норма

Совпадает с исходным или ожидаемым

Тревожный признак

Колонки переставлены — после удаления/добавления не выполнен Сдвинуть

Часто задаваемые вопросы

Как получить значение ячейки, если имя колонки хранится в переменной?

Используйте квадратные скобки: Значение = СтрокаТЗ[ИмяКолонки], где ИмяКолонки — строковая переменная. Точечное обращение работает только с именем, записанным литерально в коде.

Можно ли обойти колонки результата запроса, не выгружая его в таблицу значений?

Да. У объекта «РезультатЗапроса» есть свойство Колонки, которое обходится тем же циклом «Для Каждого». Для каждой колонки доступны имя и тип значения, что позволяет строить обработку без промежуточной выгрузки.

Как переименовать колонку таблицы значений?

У колонки есть доступное для записи свойство Имя: ТЗ.Колонки.Найти("СтароеИмя").Имя = "НовоеИмя". Новое имя должно быть уникальным и удовлетворять правилам имён идентификаторов, иначе платформа выдаст ошибку.

Почему цикл по колонкам пропускает элементы после удаления колонки внутри него?

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

Как обойти колонки у дерева значений?

Точно так же, как у таблицы: Для Каждого Колонка Из Дерево.Колонки Цикл. Различие только в данных: строки дерева образуют иерархию, поэтому для полного обхода значений нужна рекурсия по коллекции Строки каждой строки.

Можно ли отсортировать колонки по алфавиту?

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

Итог

Что важно запомнить

Обход колонок выполняется циклом «Для Каждого Колонка Из ТЗ.Колонки Цикл»; значения ячеек берутся через Строка[Колонка.Имя]. Для точечного доступа используйте Колонки.Найти, для копирования структуры — СкопироватьКолонки. Не изменяйте состав колонок внутри цикла их обхода и помните, что тип значения колонки меняется только через создание новой колонки.