Как найти значение в таблице значений 1С: пять способов с примерами кода

· 10 мин

Содержание

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

Частое заблуждение — искать метод ПолучитьСтроки. У таблицы значений его нет, конструктор синтаксиса его не подскажет, а код упадёт с ошибкой «Метод объекта не обнаружен ». Для выборки нескольких строк служат НайтиСтроки, Скопировать с отбором и запрос. Всё, что ниже, работает на платформе 8.3 в серверном коде и в толстом клиенте: в тонком клиенте таблицы значений нет.

Метод Найти: первая строка с нужным значением

Синтаксис простой:

Строка = ТЗ.Найти(<Значение>, <Колонки>);
  • 🔎 Значение — что ищем: строка, число, дата, ссылка, булево, Неопределено.
  • 📋 Колонки — имена колонок через запятую, в которых искать. Параметр необязательный: без него поиск идёт по всем колонкам.
  • ↩️ Результат — объект СтрокаТаблицыЗначений или Неопределено, если ничего не нашлось.

Пример: проверить, есть ли в таблице товар с артикулом, и прибавить количество.

НайденнаяСтрока = ТЗ.Найти(Артикул, "Артикул");
Если НайденнаяСтрока = Неопределено Тогда
	НоваяСтрока = ТЗ.Добавить();
	НоваяСтрока.Артикул = Артикул;
	НоваяСтрока.Количество = Количество;
Иначе
	НайденнаяСтрока.Количество = НайденнаяСтрока.Количество + Количество;
КонецЕсли;

Найденная строка — не копия, а сама строка таблицы. Если поменять в ней поле, изменится таблица.

Что важно знать про Найти

  • ☝️ Метод возвращает только первое совпадение. Продолжить поиск «со следующей строки» он не умеет: для повторов нужен НайтиСтроки.
  • 🧩 Если перечислить несколько колонок ("Код, Артикул"), строка найдётся, когда значение совпадёт хотя бы в одной из них. Это не поиск по двум условиям сразу.
  • 🔢 Номер найденной строки даёт ТЗ.Индекс(НайденнаяСтрока). Нумерация с нуля.

Поиск без параметра Колонки идёт по всем колонкам. Число 1 может совпасть с колонкой «Количество», хотя вы искали код. Всегда указывайте колонку явно.

НайтиСтроки: все строки по одному или нескольким условиям

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

Отбор = Новый Структура;
Отбор.Вставить("Склад", СкладОсновной);
Отбор.Вставить("Организация", Организация);

НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);

Для Каждого Строка Из НайденныеСтроки Цикл
	Строка.Цена = НоваяЦена;
КонецЦикла;

Условия в структуре соединяются через «И»: строка попадёт в результат, только если совпали все поля. Если ничего не нашлось, вернётся пустой массив, а не Неопределено. Проверка — НайденныеСтроки.Количество() = 0.

Удаление найденных строк

Массив из НайтиСтроки — отдельная коллекция. Поэтому по нему можно идти циклом и удалять строки из таблицы без риска пропустить соседние:

ПустыеСтроки = ТЗ.НайтиСтроки(Новый Структура("Количество", 0));
Для Каждого Строка Из ПустыеСтроки Цикл
	ТЗ.Удалить(Строка);
КонецЦикла;

Если же удалять прямо в цикле Для Каждого ... Из ТЗ, строки будут пропускаться. Там нужен обратный цикл по индексу.

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

Отбор и сортировка: новая таблица только с нужными строками

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

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

Здесь три шага в одном фрагменте:

  1. Скопировать(Отбор, Колонки) создаёт новую таблицу со строками, прошедшими отбор, и только с перечисленными колонками.
  2. Сортировать("Сумма Убыв") упорядочивает строки. Можно указать несколько колонок: "Склад, Сумма Убыв". Без слова Убыв сортировка по возрастанию.
  3. Итог("Сумма") возвращает сумму числовой колонки.

Изменения в копии на исходную таблицу не влияют. Это и плюс, и ловушка: если нужно править исходные данные, берите НайтиСтроки.

Найти максимум или минимум

Отдельного метода «найти максимальное значение» нет. Рабочий приём — отсортировать и взять первую строку:

Копия = ТЗ.Скопировать();
Копия.Сортировать("Сумма Убыв");
Если Копия.Количество() > 0 Тогда
	СтрокаМакс = Копия[0];
КонецЕсли;

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

Когда условие не «равно»

Найти и НайтиСтроки проверяют только равенство. Условия «больше», «не равно», «содержит подстроку» решаются циклом или запросом:

Результат = Новый Массив;
Для Каждого Строка Из ТЗ Цикл
	Если Строка.Сумма > 10000 И СтрНайти(Строка.Комментарий, "срочно") > 0 Тогда
		Результат.Добавить(Строка);
	КонецЕсли;
КонецЦикла;

СтрНайти есть в платформе начиная с 8.3.6. Он учитывает регистр, поэтому «Срочно» и «срочно» для него разные строки.

Поиск в таблице значений запросом

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

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Т.Номенклатура КАК Номенклатура,
|	Т.Количество КАК Количество,
|	Т.Сумма КАК Сумма
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
|	&ТаблицаДанных КАК Т
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ВТ.Номенклатура КАК Номенклатура,
|	СУММА(ВТ.Количество) КАК Количество
|ИЗ
|	ВТ_Данные КАК ВТ
|ГДЕ
|	ВТ.Сумма > &Порог
|	И ВТ.Номенклатура.Наименование ПОДОБНО &Шаблон
|
|СГРУППИРОВАТЬ ПО
|	ВТ.Номенклатура";

Запрос.УстановитьПараметр("ТаблицаДанных", ТЗ);
Запрос.УстановитьПараметр("Порог", 10000);
Запрос.УстановитьПараметр("Шаблон", "%кабель%");

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
	// Выборка.Номенклатура, Выборка.Количество
КонецЦикла;

Что даёт запрос по сравнению с циклом:

  • 🔗 обращение к реквизитам ссылок через точку (ВТ.Номенклатура.Наименование);
  • 🧮 группировки, итоги, РАЗЛИЧНЫЕ;
  • 🔤 поиск по шаблону через ПОДОБНО;
  • 🤝 соединение с таблицами базы — например, отобрать только товары с остатком.

Требование к типам колонок

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

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

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

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

Сравнение значений: почему строка «есть», а Найти её не видит

Большая часть вопросов «Найти возвращает Неопределено, хотя строка точно есть» сводится к сравнению. Платформа сравнивает значение вместе с типом и без приведений.

Что ищетеЧто в колонкеНайдётся?Как исправить
"100" (строка)100 (число)❌привести тип: Число("100")
"Иванов""Иванов " (пробел в конце)❌СокрЛП при заполнении колонки
"иванов""Иванов"❌цикл со сравнением ВРег
1010.00✅—
'20260107' (дата без времени)'20260107153000'❌хранить НачалоДня(Дата)
Неопределенопустая ссылка справочника❌искать пустую ссылку: Справочники.Номенклатура.ПустаяСсылка()
ссылка на элементта же ссылка✅—

Ловушка квалификаторов

Значение, записанное в типизированную колонку, приводится к её типу. Если колонка объявлена как строка длиной 10, а вы записали "Поставщик_001", в таблице окажется "Поставщик_". Поиск полной строкой ничего не найдёт. То же с числами: при точности 2 знака значение 1.005 будет сохранено округлённым.

Если у колонки составной тип или тип не задан, в ней могут соседствовать строка "5" и число 5. Поиск найдёт только значение того же типа, что вы передали.

Поиск без учёта регистра

Готового параметра нет. Решение — цикл с приведением к верхнему регистру:

Функция НайтиБезУчетаРегистра(ТЗ, ИмяКолонки, Текст)
	Искомое = ВРег(СокрЛП(Текст));
	Для Каждого Строка Из ТЗ Цикл
		Если ВРег(СокрЛП(Строка[ИмяКолонки])) = Искомое Тогда
			Возврат Строка;
		КонецЕсли;
	КонецЦикла;
	Возврат Неопределено;
КонецФункции

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

Как ускорить поиск: индексы и соответствие

Найти и НайтиСтроки без индекса просматривают таблицу целиком. На таблице в 500 строк этого не видно. Но поиск внутри цикла по другой коллекции — частый сценарий: 50 000 строк документа × 50 000 строк таблицы дают 2,5 млрд сравнений. Обработка, которая должна работать секунды, идёт десятки минут.

Индекс таблицы значений

ТЗ.Индексы.Добавить("Склад, Номенклатура");

Отбор = Новый Структура("Склад, Номенклатура");
Для Каждого СтрокаДокумента Из СтрокиДокумента Цикл
	Отбор.Склад = СтрокаДокумента.Склад;
	Отбор.Номенклатура = СтрокаДокумента.Номенклатура;
	Найденные = ТЗ.НайтиСтроки(Отбор);
	// ...
КонецЦикла;

Правила, при которых индекс реально работает:

  1. Набор колонок в индексе совпадает с ключами структуры в НайтиСтроки.
  2. Индекс добавлен один раз, до цикла поиска, а не на каждой итерации.
  3. Индексированные колонки не меняются массово во время поиска: каждое изменение пересчитывает индекс.

Структуру Отбор удобно создать один раз и только менять значения: так не плодятся лишние объекты в цикле.

Соответствие вместо таблицы

Если ключ уникален (артикул, код, ссылка), самый быстрый вариант — один раз построить Соответствие:

КартаАртикулов = Новый Соответствие;
Для Каждого Строка Из ТЗ Цикл
	КартаАртикулов.Вставить(Строка.Артикул, Строка);
КонецЦикла;

НайденнаяСтрока = КартаАртикулов.Получить(Артикул); // Неопределено, если нет

При повторяющихся артикулах в соответствии останется последняя строка с этим ключом. Если дубли важны, храните в значении массив строк.

Какой способ выбрать

ЗадачаСпособСкорость на больших таблицах
Одна строка, один разНайтинормально
Все строки по равенствуНайтиСтрокинормально, с индексом — быстро
Много поисков в циклеНайтиСтроки + индекс или Соответствиебыстро
Отдельная таблица с отборомСкопировать(Отбор)нормально
«Больше/меньше», подстрокацикл или запросзависит от объёма
Группировка, связь с базойзапросбыстро на сложной логике

Таблица значений на управляемой форме

На форме таблица значений живёт в виде реквизита. В клиентском коде это уже не ТаблицаЗначений, а коллекция данных формы. У неё есть НайтиСтроки, но нет метода Найти. Поэтому код с Объект.Товары.Найти(...) в клиентской процедуре формы падает, а тот же код на сервере с табличной частью объекта работает.

Варианты решения:

  • 🖥️ на клиенте использовать НайтиСтроки со структурой и брать первый элемент массива;
  • ⚙️ перенести поиск в серверную процедуру и получить таблицу через РеквизитФормыВЗначение("ИмяРеквизита"), а после правок вернуть её методом ЗначениеВРеквизитФормы.

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

Частые ошибки при поиске

  • ❌ Проверка результата НайтиСтроки на Неопределено. Метод всегда возвращает массив. Условие Если Найденные = Неопределено никогда не сработает, и код дальше обратится к Найденные[0] на пустом массиве.
  • ❌ Обращение к полю без проверки. ТЗ.Найти(Код, "Код").Наименование упадёт с ошибкой, если строки нет: у Неопределено полей не бывает. Сначала сохраните результат в переменную и проверьте.
  • ❌ Ожидание поиска «по всем условиям» от Найти. Перечисление колонок через запятую — это «в любой из колонок», а не «во всех сразу».
  • ❌ Удаление строк в прямом цикле по таблице. После удаления индексы сдвигаются, и следующая строка пропускается.
  • ❌ Пересоздание индекса внутри цикла. Вызов Индексы.Добавить на каждой итерации делает поиск медленнее, чем без индекса.
Диагностика: выберите симптом

Частые вопросы

Как проверить, есть ли значение в колонке, не получая строку?
Сравните результат Найти с Неопределено: Есть = ТЗ.Найти(Значение, "Колонка") <> Неопределено. Отдельного метода «Содержит» у таблицы значений нет.
Как найти строки, где значение входит в список из нескольких вариантов?
НайтиСтроки принимает одно значение на колонку. Для списка вызовите его для каждого варианта и объедините массивы либо используйте запрос с условием В (&Список).
Можно ли выгрузить колонку и искать в массиве?
Да: ТЗ.ВыгрузитьКолонку("Артикул") вернёт массив, а Массив.Найти(Значение) — индекс элемента или Неопределено. Индекс совпадает с индексом строки в таблице, пока таблицу не сортировали и не меняли.
Ищет ли НайтиСтроки по колонке со ссылкой на документ?
Да, ссылки сравниваются как обычные значения. Передайте в структуру ту же ссылку — найдутся все строки с этим документом.
Чем поиск в таблице значений отличается от поиска в табличной части документа?
У табличной части объекта на сервере тоже есть Найти и НайтиСтроки с тем же поведением. Но индексы и Скопировать с отбором — возможности именно таблицы значений: для них табличную часть выгружают методом Выгрузить().