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