Заполнение колонок Таблицы значений: код и методы
Содержание
Чтобы записать значение в колонку Таблицы значений, обращаются к ячейке через строку и имя колонки: Строка.Количество = 5. Для одной строки хватит прямого присваивания, для всей таблицы — цикл Для Каждого или встроенные методы ЗаполнитьЗначения и ЗагрузитьКолонку.
Способ зависит от объёма. Несколько строк — присваивайте вручную. Одинаковое значение во все строки — метод ЗаполнитьЗначения. Готовый массив данных — ЗагрузитьКолонку. Расчёт для каждой строки отдельно — цикл. Ниже разберём каждый вариант с кодом, который можно вставить в модуль и запустить.
Создаём таблицу и описываем колонки
Таблица значений существует только в памяти — это не объект базы данных, а структура для промежуточных расчётов. Создаётся оператором Новый:
ТЗ = Новый ТаблицаЗначений;
Пустая таблица колонок не имеет. Их добавляют методом Колонки.Добавить. Первый параметр — имя колонки, по которому вы потом обращаетесь к ячейке:
ТЗ.Колонки.Добавить("Наименование");
ТЗ.Колонки.Добавить("Количество");
ТЗ.Колонки.Добавить("Цена");
Такие колонки — без типа. В них можно положить что угодно: число, строку, ссылку. Это гибко, но опасно: опечатка в расчёте попадёт в ячейку молча. Поэтому колонкам лучше задавать тип через ОписаниеТипов — вторым параметром:
ТЗ.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2)));
Здесь КвалификаторыЧисла(15, 2) — это 15 знаков всего и 2 после запятой. Для строки можно задать длину через КвалификаторыСтроки, для даты — состав (дата, время, дата и время).
Полный синтаксис метода: Колонки.Добавить(Имя, ТипыЗначений, Заголовок, Ширина). Третий параметр — заголовок для показа в форме, четвёртый — ширина колонки. Если таблица нужна только для расчёта и на форму не выводится, хватит первых двух.
Проверить, что колонка есть, можно методом Найти — он вернёт Неопределено, если колонки нет:
Если ТЗ.Колонки.Найти("Цена") = Неопределено Тогда
ТЗ.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
КонецЕсли;
Добавляем строки и пишем в ячейки напрямую
Пока в таблице нет строк, заполнять нечего. Строку добавляет метод Добавить — он возвращает саму новую строку, и к её колонкам сразу обращаются через точку:
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Наименование = "Бумага А4";
НоваяСтрока.Количество = 10;
НоваяСтрока.Цена = 320.50;
К той же ячейке можно обратиться и по индексу колонки, но имя надёжнее: при перестановке колонок индекс сломается, а имя — нет.
Если строку нужно вставить не в конец, а в определённую позицию, используйте Вставить с номером (нумерация с нуля):
ПерваяСтрока = ТЗ.Вставить(0); // вставит в начало
ПерваяСтрока.Наименование = "Итого";
Заполнить уже существующую строку по её номеру тоже просто — обращение через индекс таблицы:
ТЗ[0].Количество = 100; // первая строка
ТЗ[ТЗ.Количество() - 1].Цена = 0; // последняя строка
ТЗ.Количество() — это метод со скобками, а не свойство. Частая ошибка новичков — написать ТЗ.Количество без скобок и получить непонятный результат.
Заполняем колонку в цикле
Когда значение в каждой строке своё — его считают или берут из другого источника — нужен обход всех строк. Самый читаемый вариант — цикл Для Каждного:
Для Каждого Строка Из ТЗ Цикл
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
Колонку Сумма при этом надо добавить заранее, иначе обращение к несуществующей колонке вызовет ошибку.
Если внутри цикла нужен номер строки — например, для нумерации — берут цикл со счётчиком и обращаются по индексу:
Для Сч = 0 По ТЗ.Количество() - 1 Цикл
ТЗ[Сч].НомерСтроки = Сч + 1;
КонецЦикла;
Скопировать данные из одной таблицы в колонку другой тоже удобно циклом — при условии, что строки идут в том же порядке:
Для Каждого Строка Из ТЗИсточник Цикл
НоваяСтрока = ТЗПриёмник.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
КонецЦикла;
Метод ЗаполнитьЗначенияСвойств переносит значения всех одноимённых колонок за один вызов — не нужно перечислять каждую. Если имена колонок в источнике и приёмнике совпадают, это самый короткий способ скопировать строки.
Не удаляйте строки внутри прямого цикла Для Каждого: после удаления обход собьётся. Если строки надо и перебрать, и часть удалить, идите обратным циклом по счётчику: Для Сч = ТЗ.Количество() - 1 По 0 Цикл — и удаляйте ТЗ.Удалить(Сч).
Массовое заполнение одним методом
Когда во все строки колонки нужно положить одно и то же значение, цикл избыточен. Для этого есть метод ЗаполнитьЗначения:
ТЗ.ЗаполнитьЗначения(0, "Количество");
Первый параметр — значение, второй — колонки через запятую в одной строке. Можно перечислить несколько:
ТЗ.ЗаполнитьЗначения(0, "Количество, Сумма, Скидка");
Если второй параметр не указывать, значение запишется во все колонки всех строк — пользуйтесь этим осторожно.
Другая частая задача — загрузить в колонку готовый массив значений. Для этого есть ЗагрузитьКолонку:
МассивЦен = Новый Массив;
МассивЦен.Добавить(100);
МассивЦен.Добавить(200);
МассивЦен.Добавить(300);
ТЗ.ЗагрузитьКолонку(МассивЦен, "Цена");
Размер массива должен совпадать с числом строк в таблице. Если элементов в массиве меньше, чем строк, лишние строки получат Неопределено; если больше — часть данных просто не попадёт.
Обратный метод — ВыгрузитьКолонку — достаёт колонку в массив. Связка «выгрузил из одной таблицы → загрузил в другую» переносит колонку целиком:
Цены = ТЗИсточник.ВыгрузитьКолонку("Цена");
ТЗПриёмник.ЗагрузитьКолонку(Цены, "Цена");
Сравним способы:
| Способ | Когда применять | Что учесть |
|---|---|---|
Присваивание Строка.Колонка | 1–2 строки, точечная правка | Строка должна существовать |
Цикл Для Каждого | значение в каждой строке своё | Колонка должна быть добавлена заранее |
ЗаполнитьЗначения | одно значение во все строки | Колонки перечисляются одной строкой |
ЗагрузитьКолонку | есть готовый массив данных | Длина массива = числу строк |
Контроль типов и обработка ошибок
Если колонка описана типом, присваиваемое значение приводится к этому типу автоматически. Строка "5" в числовой колонке станет числом 5. Но если привести нельзя — например, в числовую колонку положить слово "пять" — вы получите не ошибку, а значение по умолчанию (для числа это 0). Расчёт тихо испортится.
Поэтому входные данные проверяйте до записи. Для разбора строки в число подойдёт попытка с перехватом:
Попытка
Строка.Количество = Число(ВходноеЗначение);
Исключение
Строка.Количество = 0;
Сообщить("Не удалось распознать количество: " + ВходноеЗначение);
КонецПопытки;
Проверить тип уже лежащего в ячейке значения можно функцией ТипЗнч:
Если ТипЗнч(Строка.Цена) = Тип("Число") Тогда
Строка.Сумма = Строка.Количество * Строка.Цена;
Иначе
Строка.Сумма = 0;
КонецЕсли;
Отдельная ловушка — обращение к несуществующей колонке. Такой вызов прерывает выполнение с ошибкой «Поле объекта не обнаружено». Если имя колонки приходит извне (из настройки, из параметра), проверьте его через Колонки.Найти перед обращением, как показано в первом разделе.
Для составных данных задавайте колонке несколько типов сразу: Новый ОписаниеТипов("Число, Строка"). Тогда в ячейку можно класть и число, и строку, а приведение отключится.
Производительность на больших объёмах
На сотне строк разницы в способах нет. На десятках и сотнях тысяч строк выбор метода меняет время работы в разы.
Правила для больших таблиц:
- 📦 Массовые методы вместо цикла.
ЗаполнитьЗначенияиЗагрузитьКолонкуработают заметно быстрее, чем присваивание в цикле строка за строкой. Если задача сводится к ним — используйте их. - 🔍 Индексы для поиска. Если вы многократно ищете строки методом
НайтиилиНайтиСтроки, добавьте индекс по колонкам поиска:ТЗ.Индексы.Добавить("Наименование"). Без индекса поиск идёт перебором и на больших таблицах тормозит. - 🚫 Не ищите в цикле без индекса. Конструкция «для каждой строки одной таблицы ищу строку в другой» без индекса даёт квадратичную сложность: 10 000 строк превращаются в десятки миллионов сравнений.
- 🧮 Считайте один раз. Не вызывайте
ТЗ.Количество()в условии цикла по счётчику на огромных объёмах без нужды — сохраните в переменную, если таблица в цикле не меняется.
Для поиска и выборки по индексу используйте НайтиСтроки со структурой отбора — он вернёт массив подходящих строк:
ТЗ.Индексы.Добавить("Наименование");
Отбор = Новый Структура("Наименование", "Бумага А4");
Найденные = ТЗ.НайтиСтроки(Отбор);
Для Каждого Строка Из Найденные Цикл
Строка.Количество = Строка.Количество + 1;
КонецЦикла;
Если из большой таблицы нужна только часть строк или колонок, не перебирайте всё вручную — метод Скопировать сразу вернёт новую таблицу по отбору:
ТЗТоваров = ТЗ.Скопировать(Отбор, "Наименование, Количество");
Заполнение колонки из запроса
На практике таблицу редко заполняют вручную — чаще данные приходят из запроса. Результат запроса выгружается в Таблицу значений методом Выгрузить, и дальше вы работаете с ней как с обычной таблицей:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ Номенклатура.Наименование КАК Наименование,
| Остатки.КоличествоОстаток КАК Количество
|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки() КАК Остатки";
ТЗ = Запрос.Выполнить().Выгрузить();
Колонки такой таблицы создаются автоматически — по псевдонимам из запроса (КАК Наименование). Их не нужно добавлять вручную, но вы можете дописать расчётную колонку и заполнить её по данным запроса:
ТЗ.Колонки.Добавить("Дефицит", Новый ОписаниеТипов("Булево"));
Для Каждого Строка Из ТЗ Цикл
Строка.Дефицит = (Строка.Количество <= 0);
КонецЦикла;
Если нужны не все строки результата, отбор удобнее задать в самом запросе условием ГДЕ, а не перебирать таблицу потом. База отфильтрует данные быстрее, и в память попадёт меньше строк.
Частые вопросы
Как добавить колонку в уже заполненную таблицу?
ТЗ.Колонки.Добавить("НоваяКолонка") в любой момент. Во всех существующих строках новая ячейка получит значение по умолчанию (для типизированной колонки — значение её типа, для нетипизированной — Неопределено). Заполнить её потом можно циклом или ЗаполнитьЗначения.Чем `ЗагрузитьКолонку` отличается от цикла?
ЗагрузитьКолонку переносит готовый массив за один вызов и работает быстрее на больших объёмах. Цикл нужен, когда значение каждой строки вычисляется, а не берётся из готового массива.Почему в числовой колонке оказался 0, хотя я записал строку?
Число() в блоке Попытка … Исключение до присваивания.Как скопировать колонку из одной таблицы в другую?
ВыгрузитьКолонку("Имя") и загрузите в приёмник методом ЗагрузитьКолонку(Массив, "Имя"). Число строк в обеих таблицах должно совпадать.Можно ли заполнить сразу несколько колонок одним значением?
ТЗ.ЗаполнитьЗначения(0, "Количество, Сумма, Скидка"). Без второго параметра значение запишется во все колонки.