Колонки таблицы значений 1С 8.3: доступ по имени, индексу и в цикле

· 9 мин

Содержание

Чтобы обратиться к колонке таблицы значений в 1С, берут строку и пишут имя колонки через точку: Стр.Сумма. Если имя приходит в переменной, используют скобки Стр["Сумма"], если известен только номер — Стр[2] или Стр.Получить(2). Сама колонка как объект (имя, тип, заголовок) живёт в коллекции ТЗ.Колонки.

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

Пять способов обратиться к колонке: сравнение

Значение ячейки таблицы значений всегда читается через строку (СтрокаТаблицыЗначений). Колонка задаёт, какое поле строки нужно. Вот все рабочие варианты на одной таблице.

СпособПримерКогда применятьПодводный камень
Через точкуСтр.СуммаИмя известно заранееОпечатка видна только при выполнении
По имени в скобкахСтр["Сумма"]Имя в переменнойСтроку легко ошибочно собрать
По индексуСтр[2]Перебор всех колонокИндекс съезжает при вставке колонки
Метод строкиСтр.Получить(2)Код в стиле коллекцийПринимает только число
Через объект колонкиСтр[Кол.Имя]Цикл по ТЗ.КолонкиЛишнее чтение имени на каждой итерации

Пример таблицы, на которой проверены все фрагменты статьи:

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

Стр = ТЗ.Добавить();
Стр.Номенклатура = "Бумага А4";
Стр.Количество = 10;
Стр.Сумма = 3500;

Индексы колонок здесь такие: Номенклатура — 0, Количество — 1, Сумма — 2. Нумерация всегда с нуля.

Обращение к колонке по имени: точка и квадратные скобки

Через точку

Самый читаемый вариант. Работает и на чтение, и на запись:

Стр.Сумма = Стр.Количество * 350;
Сообщить(Стр.Номенклатура);

Конкретную строку можно взять по её номеру в таблице: ТЗ[0].Сумма или ТЗ.Получить(0).Сумма. Оба варианта равнозначны.

По имени в квадратных скобках

Скобки принимают строку с именем колонки. Синтаксис нужен, когда имя хранится в переменной или приходит параметром:

ИмяПоля = "Сумма";
Стр[ИмяПоля] = Стр[ИмяПоля] * 1.2;

Регистр букв в имени не важен: Стр["сумма"] и Стр.СУММА дадут одну и ту же колонку. Пробелы и точки в имени недопустимы, поэтому строку вида "Сумма с НДС" скобки не примут — колонку с таким именем просто нельзя создать.

Если имя колонки берётся из настроек пользователя или из внешнего файла, сначала проверьте его через ТЗ.Колонки.Найти(ИмяПоля). Иначе неверное имя уронит обработку посередине.

Работа с колонками по индексу

Индекс колонки — её номер в коллекции ТЗ.Колонки, начиная с нуля. Строка таблицы принимает этот номер в квадратных скобках:

Стр[0] = "Скрепки";  // Номенклатура
Стр[1] = 5;          // Количество
Стр[2] = Стр[1] * 40; // Сумма = 200

Узнать индекс колонки по её имени:

Кол = ТЗ.Колонки.Найти("Сумма");
Индекс = ТЗ.Колонки.Индекс(Кол); // 2

Последний индекс равен ТЗ.Колонки.Количество() - 1. Обращение к номеру за этой границей вызывает ошибку выполнения, поэтому в универсальном коде границу берут из коллекции, а не пишут числом.

Индекс зависит от порядка колонок. Если кто-то добавит колонку методом Вставить(0, …) или переставит её через Сдвинуть(), все жёстко прописанные номера начнут указывать не туда. В прикладном коде с известной структурой обращайтесь по имени, а не по номеру.

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

Методы строки Получить() и Установить()

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

  • 🔹 Получить(Индекс) — возвращает значение колонки с этим номером;
  • 🔹 Установить(Индекс, Значение) — записывает значение в колонку.
Стр = ТЗ[0];
Количество = Стр.Получить(1);
Стр.Установить(2, Количество * 350);

По результату это то же самое, что Стр[1] и Стр[2] = …. Методы удобны, когда код пишется в общем стиле работы с коллекциями или передаётся в процедуру, где явный вызов читается понятнее скобок.

Два частых заблуждения:

  1. Метода УстановитьЗначение() у строки таблицы значений нет. Правильное имя — Установить().
  2. Получить() и Установить() принимают только число. Имя колонки строкой туда не передаётся — для имени используйте Стр["Сумма"].

Не путайте с ТЗ.Получить(Индекс): этот метод самой таблицы возвращает строку, а не значение колонки.

Коллекция Колонки: создать, найти, переименовать, удалить

ТЗ.Колонки — коллекция объектов КолонкаТаблицыЗначений. У каждой колонки четыре свойства: Имя, ТипЗначения, Заголовок, Ширина.

ЗадачаКод
Добавить в конецТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"))
Вставить на позициюТЗ.Колонки.Вставить(1, "Артикул")
Найти по имениКол = ТЗ.Колонки.Найти("Цена")
Число колонокТЗ.Колонки.Количество()
ПереименоватьКол.Имя = "ЦенаБезНДС"
ПереставитьТЗ.Колонки.Сдвинуть(Кол, -1)
УдалитьТЗ.Колонки.Удалить(Кол)

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

Если ТЗ.Колонки.Найти("Цена") = Неопределено Тогда
    ТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
КонецЕсли;

Колонки можно добавлять и удалять, когда в таблице уже есть строки. Новая колонка в существующих строках заполнится значением по умолчанию для своего типа, у числа это 0.

Зачем задавать тип колонки

Тип в Добавить() необязателен, но лучше его указать:

  • 📌 без типа Итог() и сортировка ведут себя непредсказуемо на смешанных значениях;
  • 📌 если таблицу передают в запрос параметром и выбирают из неё во временную таблицу (ИЗ &ТЗ КАК Т), колонка без типа вызывает ошибку;
  • 📌 типизированная колонка сама приводит значение: в колонку Число строка не запишется как строка.

Проверить, что у двух таблиц одинаковые колонки

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

Недостающие = Новый Массив;
Для Каждого Кол Из Источник.Колонки Цикл
    Если Приемник.Колонки.Найти(Кол.Имя) = Неопределено Тогда
        Недостающие.Добавить(Кол.Имя);
    КонецЕсли;
КонецЦикла;

Если Недостающие.Количество() > 0 Тогда
    Сообщить("Нет колонок: " + СтрСоединить(Недостающие, ", "));
КонецЕсли;

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

Заголовок и имя — не одно и то же

Имя используется в коде, Заголовок — в интерфейсе: его видит пользователь в табличном поле и при выводе в табличный документ. Имя — идентификатор без пробелов, заголовок может быть любой строкой: "Сумма с НДС, руб.". Если заголовок не задан, платформа показывает имя колонки. Обращаться к колонке по заголовку нельзя: ни точка, ни скобки, ни Найти() его не учитывают.

Перебор колонок и строк в цикле

Классическая задача — пройти все ячейки таблицы, не зная её структуры. Внешний цикл по строкам, внутренний по колонкам:

Для Каждого Стр Из ТЗ Цикл
    Для Каждого Кол Из ТЗ.Колонки Цикл
        Сообщить(СтрШаблон("%1 = %2", Кол.Имя, Стр[Кол.Имя]));
    КонецЦикла;
КонецЦикла;

То же по индексам — быстрее на больших таблицах, потому что не ищется имя:

ЧислоКолонок = ТЗ.Колонки.Количество();
Для Каждого Стр Из ТЗ Цикл
    Для Индекс = 0 По ЧислоКолонок - 1 Цикл
        Значение = Стр[Индекс];
    КонецЦикла;
КонецЦикла;

Удаление колонок в цикле

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

Всего = ТЗ.Колонки.Количество();
Для Сч = 1 По Всего Цикл
    Кол = ТЗ.Колонки[Всего - Сч];
    Если СтрНачинаетсяС(Кол.Имя, "Служ") Тогда
        ТЗ.Колонки.Удалить(Кол);
    КонецЕсли;
КонецЦикла;

Цикл берёт колонки с индекса Всего - 1 до 0. Удаление очередной колонки не задевает те, что левее, поэтому ни одна не пропадает из проверки.

Колонки, имя которых известно только при выполнении

Динамические колонки появляются в отчётах «по месяцам», в загрузке из Excel и в выгрузке результата запроса. Имя колонки собирается строкой, а обращение идёт через скобки.

Колонки по периодам

Для Месяц = 1 По 12 Цикл
    ИмяКолонки = "Месяц" + Формат(Месяц, "ЧЦ=2; ЧВН=; ЧГ=0");
    ТЗ.Колонки.Добавить(ИмяКолонки, Новый ОписаниеТипов("Число"), Формат(Месяц, "ЧГ=0"));
КонецЦикла;

Стр[ИмяКолонки] = 1500; // запишет в "Месяц12"

Формат ЧВН= дополняет номер ведущим нулём: получаются Месяц01…Месяц12, и колонки сортируются по имени правильно. Третий параметр — заголовок, который увидит пользователь.

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

После Результат.Выгрузить() имена колонок совпадают с псевдонимами полей запроса (КАК Сумма). Поле без псевдонима получает имя, которое платформа сформирует сама, и угадывать его неудобно. Давайте псевдоним каждому полю, к которому будете обращаться.

Массовое заполнение колонок из структуры

Если значения пришли структурой с теми же ключами, не нужно писать по строке на каждую колонку:

Данные = Новый Структура("Номенклатура, Количество, Сумма", "Тонер", 2, 4800);
ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), Данные);

Ключи, которых нет среди колонок, просто игнорируются.

Работа с колонкой целиком

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

ЗадачаМетод
Все значения колонки в массивМассив = ТЗ.ВыгрузитьКолонку("Сумма")
Записать массив в колонкуТЗ.ЗагрузитьКолонку(Массив, "Сумма")
Сумма по колонкеТЗ.Итог("Сумма")
Одинаковое значение во все строкиТЗ.ЗаполнитьЗначения(0, "Сумма")
Найти строки по значениям колонокТЗ.НайтиСтроки(Новый Структура("Номенклатура", "Тонер"))
Группировка с суммированиемТЗ.Свернуть("Номенклатура", "Количество, Сумма")
СортировкаТЗ.Сортировать("Сумма Убыв")
Копия только нужных колонокТЗ.Скопировать(, "Номенклатура, Сумма")
Пустая таблица той же структурыТЗ.СкопироватьКолонки()

Три приёма, которые сильно ускоряют код:

  1. Уникальные значения колонки. Копия = ТЗ.Скопировать(, "Номенклатура"); Копия.Свернуть("Номенклатура"); — затем Копия.ВыгрузитьКолонку(0). Исходная таблица не меняется.
  2. Индекс по колонке поиска. Перед многократным НайтиСтроки() добавьте ТЗ.Индексы.Добавить("Номенклатура"). На больших таблицах поиск перестаёт перебирать все строки.
  3. Пересчёт колонки массивом. Выгрузить колонку, пересчитать массив, загрузить обратно через ЗагрузитьКолонку(). Количество элементов массива должно совпадать с числом строк таблицы.

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

Таблица значений существует только на сервере и в толстом клиенте. В модуле формы на клиенте её нет: реквизит формы типа «Таблица значений» там представлен коллекцией данных формы. Чтобы работать с колонками через Колонки и методы выше, переведите реквизит в значение на сервере: РеквизитФормыВЗначение("Товары"), а после изменений — ЗначениеВРеквизитФормы(ТЗ, "Товары").

Ошибки при обращении к колонкам

Почти все сбои сводятся к тому, что колонки нет, имя собрано неверно или индекс вышел за границу.

Диагностика: выберите симптом

Ещё одна тихая ошибка — склейка числа со строкой при сборке имени. "Месяц" + Месяц на значении 1000 и больше даст неразрывный пробел-разделитель групп, и имя станет недопустимым. Числа в имена колонок всегда переводите через Формат(…, "ЧГ=0").