Разработка и Конфигурация · 13 мин
Как заполнить колонку таблицы значений в 1С
Как заполнить колонку таблицы значений в 1С: цикл по строкам, метод ЗаполнитьЗначения, заполнение из запроса и другой таблицы. Примеры кода и типичные ошибки.
Таблица значений — один из базовых объектов встроенного языка 1С, который используется для промежуточного хранения и обработки данных: выгрузки из запросов, подготовки табличных частей, обмена между процедурами. Задача заполнить одну колонку возникает постоянно: проставить признак обработки, рассчитать сумму, подставить значение по умолчанию или перенести данные из другой структуры.
Способ заполнения зависит от источника данных и от того, существует ли колонка. Если колонки нет, обращение к ней вызовет ошибку «Поле объекта не обнаружено», поэтому сначала её добавляют методом Колонки.Добавить() с указанием типа. Дальше применяют один из трёх подходов: массовое заполнение одним значением, построчное вычисление в цикле или перенос значений из запроса либо другой таблицы.
Важно понимать разницу между таблицей значений на сервере и табличным полем на форме: заполнение данных и отображение данных — разные операции. Ниже разобраны рабочие приёмы с примерами кода, ограничения каждого метода и способы проверить результат.
Добавление колонки перед заполнением
Прежде чем записывать данные, убедитесь, что колонка существует. Если таблица получена выгрузкой из запроса, колонки уже созданы по полям выборки. Если таблица строится программно, колонку добавляют явно:
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Таблица.Колонки.Добавить("Обработано", Новый ОписаниеТипов("Булево"));
Тип колонки определяет, какие значения в неё можно записать без ошибки преобразования. Если заранее неизвестно, что попадёт в колонку, используют составной тип, например Новый ОписаниеТипов("Число,Строка"). Но злоупотреблять составными типами не стоит: сравнение и сортировка по таким колонкам работают медленнее и менее предсказуемо.
Проверить существование колонки можно через Таблица.Колонки.Найти("ИмяКолонки") — метод вернёт Неопределено, если колонки нет. Это полезно в универсальных процедурах, где структура таблицы не гарантирована:
Если Таблица.Колонки.Найти("Сумма") = Неопределено Тогда
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
КонецЕсли;
Заполнение всей колонки одним значением
Когда во все строки нужно записать одинаковое значение — признак, дату документа, константу расчёта — используют метод ЗаполнитьЗначения(). Это самый короткий и быстрый способ, цикл не требуется:
// Проставить признак во все строки
Таблица.ЗаполнитьЗначения(Истина, "Обработано");
// Проставить текущую дату
Таблица.ЗаполнитьЗначения(ТекущаяДатаСеанса(), "ДатаЗагрузки");
Первый параметр — значение, второй — строка с именами колонок через запятую. Можно заполнить сразу несколько колонок: Таблица.ЗаполнитьЗначения(0, "Сумма,СуммаНДС"). Имена указываются строкой, поэтому опечатка не будет поймана синтаксической проверкой — ошибка проявится только при выполнении.
Метод перезаписывает существующие значения безусловно. Если нужно заполнить только пустые ячейки, ЗаполнитьЗначения не подходит — используйте цикл с проверкой ЗначениеЗаполнено(Строка.Колонка).
Построчное заполнение в цикле
Если значение колонки вычисляется для каждой строки индивидуально, применяют обход таблицы в цикле Для Каждого. Внутри цикла обращение к ячейке идёт через точку: Строка.ИмяКолонки.
Для Каждого Строка Из Таблица Цикл
Строка.Сумма = Строка.Цена * Строка.Количество;
КонецЦикла;
Заполнение с условием
Частый сценарий — заполнить колонку только для строк, удовлетворяющих условию. Условие проверяется внутри цикла:
Для Каждого Строка Из Таблица Цикл
Если Строка.Количество > 0 Тогда
Строка.ПризнакОтгрузки = Истина;
Иначе
Строка.ПризнакОтгрузки = Ложь;
КонецЕсли;
КонецЦикла;
Если обрабатывать нужно только часть строк по отбору, эффективнее сначала получить их через Таблица.НайтиСтроки(Отбор) и обойти полученный массив — так не придётся проверять условие для каждой строки большой таблицы.
Заполнение с номером строки
Для нумерации строк или когда нужен индекс, используют счётчик либо цикл Для:
Номер = 1;
Для Каждого Строка Из Таблица Цикл
Строка.НомерСтроки = Номер;
Номер = Номер + 1;
КонецЦикла;
Заполнение колонки из запроса или другой таблицы
Когда данные для колонки уже есть в информационной базе, правильнее получить их запросом, а не вычислять в цикле обращениями к реквизитам. Два рабочих подхода:
Первый — поместить таблицу во временную таблицу запроса и соединить с нужными данными. Выгрузка результата даст таблицу с уже заполненной колонкой:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура,
| Т.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ &Таблица КАК Т
|;
|ВЫБРАТЬ
| Т.Номенклатура,
| Т.Количество,
| ЕСТЬNULL(Цены.Цена, 0) КАК Цена
|ИЗ ВТ_Товары КАК Т
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ) КАК Цены
| ПО Т.Номенклатура = Цены.Номенклатура";
Запрос.УстановитьПараметр("Таблица", Таблица);
Запрос.УстановитьПараметр("Дата", ТекущаяДатаСеанса());
Таблица = Запрос.Выполнить().Выгрузить();
Второй — построить соответствие «ключ → значение» по выборке запроса и заполнить колонку в цикле по нему. Соответствие ищет значение за постоянное время, что намного быстрее поиска по таблице вложенным циклом:
Цены = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Цены.Вставить(Выборка.Номенклатура, Выборка.Цена);
КонецЦикла;
Для Каждого Строка Из Таблица Цикл
Цена = Цены[Строка.Номенклатура];
Строка.Цена = ?(Цена = Неопределено, 0, Цена);
КонецЦикла;
Для переноса колонки из другой таблицы значений с совпадающим порядком строк достаточно цикла по индексу: Таблица1[Инд].Цена = Таблица2[Инд].Цена. Если порядок не совпадает, соединяйте таблицы запросом или соответствием по ключевому полю.
Сравнение вариантов
Одно значение во все строки. Самый быстрый вариант, но не подходит для вычисляемых данных и выборочного заполнения.
Универсальный способ для вычисляемых значений и условий. На больших таблицах (десятки тысяч строк) с обращениями к БД внутри цикла работает медленно.
Оптимален, когда данные колонки хранятся в базе. Требует типизированных колонок исходной таблицы и права на чтение нужных объектов.
Быстрый перенос значений по ключу между таблицами. Требует уникальности ключа, иначе значение перезапишется последним.
Заполнение колонки табличной части и данных формы
Табличная часть документа и реквизит формы типа «ТаблицаЗначений» заполняются по тем же принципам, но с отличиями в синтаксисе. У табличной части объекта колонки уже определены метаданными, добавлять их нельзя — только заполнять:
Для Каждого Строка Из Объект.Товары Цикл
Строка.Сумма = Строка.Цена * Строка.Количество;
КонецЦикла;
На управляемой форме реквизит типа «ТаблицаЗначений» доступен как ДанныеФормыКоллекция. Обход строк работает так же, но передавать такую коллекцию в запрос напрямую нельзя — сначала её выгружают:
ТаблицаДляЗапроса = РеквизитФормыВЗначение("ТаблицаФормы");
// ... работа с запросом
ЗначениеВРеквизитФормы(ТаблицаДляЗапроса, "ТаблицаФормы");
Метод ЗаполнитьЗначения() доступен и у табличных частей, и у данных формы. Учитывайте, что на форме массовое заполнение большой таблицы стоит выполнять в серверной процедуре с директивой &НаСервере, чтобы не гонять данные между клиентом и сервером на каждую строку.
- 1Определите источник значений: константа, вычисление по строке, данные из базы или другая таблица.
- 2Проверьте наличие колонки через Колонки.Найти() и при необходимости добавьте её с правильным типом.
- 3Выберите метод: ЗаполнитьЗначения для одного значения, цикл для вычислений, запрос для данных из базы.
- 4Выполните заполнение и проверьте результат на нескольких строках, включая граничные случаи (пустые значения, нули).
- 5Для таблицы на форме убедитесь, что изменения выполняются на сервере и отображаются в интерфейсе.
Производительность и типичные ошибки
Главная ошибка при заполнении колонки — обращение к базе данных внутри цикла: Строка.Склад = Строка.Документ.Склад или вызов запроса на каждой итерации. Каждое такое обращение — отдельный запрос к СУБД, и на тысяче строк время выполнения вырастает на порядки. Правильный приём: один запрос ко всем нужным данным и заполнение через соответствие.
Вторая группа ошибок связана с типами. Запись строки в числовую колонку даст ошибку преобразования; запись NULL из запроса в колонку без обработки приведёт к проблемам при последующих сравнениях — используйте ЕСТЬNULL() в тексте запроса. Ещё один частый случай: попытка заполнить колонку, которой нет, из-за опечатки в имени, переданном строкой.
Проверка результата заполнения
После заполнения полезно убедиться, что колонка содержит ожидаемые данные. Для отладки достаточно вывести несколько строк в сообщение или воспользоваться отладчиком, поставив точку останова после цикла и посмотрев таблицу через «Вычислить выражение».
Программная проверка полноты заполнения делается подсчётом строк с пустым значением:
Пустых = 0;
Для Каждого Строка Из Таблица Цикл
Если Не ЗначениеЗаполнено(Строка.Цена) Тогда
Пустых = Пустых + 1;
КонецЕсли;
КонецЦикла;
Для колонок-итогов сравните контрольную сумму: Таблица.Итог("Сумма") должен совпасть с ожидаемым итогом источника. Расхождение — признак пропущенных строк, дублей или неверной формулы расчёта.
Как проверить результат
Совпадает с количеством до заполнения
Строки появились или исчезли — цикл модифицировал состав таблицы
Все строки заполнены ожидаемыми данными, типы соответствуют колонке
Пустые значения, NULL или ошибки преобразования типов
Таблица.Итог() совпадает с контрольной суммой источника
Расхождение — есть пропуски, дубли или ошибка в формуле
Заполнение большой таблицы занимает секунды
Минуты — вероятно, запросы к БД внутри цикла
Частые вопросы
Как заполнить колонку значением по умолчанию только в пустых строках?
Метод ЗаполнитьЗначения перезаписывает всё, поэтому используйте цикл с проверкой: Если Не ЗначениеЗаполнено(Строка.Колонка) Тогда Строка.Колонка = ЗначениеПоУмолчанию. Для ускорения можно сначала получить пустые строки через НайтиСтроки с отбором по Неопределено или пустому значению соответствующего типа.
Можно ли заполнить колонку без цикла, если значения разные?
Да, если значения берутся из базы: поместите таблицу во временную таблицу запроса, соедините с источником и выгрузите результат — колонка будет заполнена на стороне СУБД. Без запроса и без цикла разные значения по строкам присвоить невозможно.
Почему возникает ошибка «Поле объекта не обнаружено» при заполнении?
Обращение идёт к колонке, которой нет в таблице: либо её не добавили, либо опечатка в имени (имена чувствительны к точному написанию, хотя и не к регистру). Проверьте состав через Таблица.Колонки в отладчике и добавьте недостающую колонку методом Колонки.Добавить().
Как скопировать колонку из одной таблицы значений в другую?
Если строки совпадают по порядку — циклом по индексу: Таблица2[Инд].Колонка = Таблица1[Инд].Колонка. Если порядок разный, но есть общий ключ, постройте соответствие «ключ → значение» по первой таблице и заполните вторую в цикле по этому соответствию.
Чем заполнение колонки табличной части отличается от таблицы значений?
Синтаксис заполнения одинаков — цикл и присваивание через точку. Различия: колонки табличной части заданы метаданными и добавить их нельзя; у табличной части нет метода Итог() (сумму считают в цикле); изменение объекта документа требует последующей записи, иначе данные не сохранятся.
Как заполнить колонку на управляемой форме, чтобы не тормозило?
Выполняйте заполнение в серверной процедуре с директивой &НаСервере. Если нужен запрос, выгрузите реквизит формы через РеквизитФормыВЗначение, обработайте как обычную таблицу значений и загрузите обратно через ЗначениеВРеквизитФормы. Клиентский цикл по большой таблице формы вызывает серверные обращения на каждую строку и работает медленно.
Что важно запомнить
Перед заполнением убедитесь, что колонка существует и имеет подходящий тип. Одинаковое значение во все строки ставится методом ЗаполнитьЗначения, вычисляемые значения — циклом Для Каждого, данные из базы — запросом с временной таблицей или соответствием. Не обращайтесь к базе внутри цикла и проверяйте результат по итогам и количеству пустых значений.