Как найти значение в таблице значений 1С: пять способов с примерами кода
Содержание
Чтобы найти значение в таблице значений 1С, вызовите ТЗ.Найти(Значение, "ИмяКолонки") — метод вернёт первую подходящую строку или Неопределено. Если нужны все строки по условию, используйте ТЗ.НайтиСтроки(Новый Структура("Колонка", Значение)): он вернёт массив строк.
Частое заблуждение — искать метод ПолучитьСтроки. У таблицы значений его нет, конструктор синтаксиса его не подскажет, а код упадёт с ошибкой «Метод объекта не обнаружен
». Для выборки нескольких строк служат НайтиСтроки, Скопировать с отбором и запрос. Всё, что ниже, работает на платформе 8.3 в серверном коде и в толстом клиенте: в тонком клиенте таблицы значений нет.
Метод Найти: первая строка с нужным значением
Синтаксис простой:
Строка = ТЗ.Найти(<Значение>, <Колонки>);
- 🔎
Значение— что ищем: строка, число, дата, ссылка, булево,Неопределено. - 📋
Колонки— имена колонок через запятую, в которых искать. Параметр необязательный: без него поиск идёт по всем колонкам. - ↩️ Результат — объект
СтрокаТаблицыЗначенийилиНеопределено, если ничего не нашлось.
Пример: проверить, есть ли в таблице товар с артикулом, и прибавить количество.
НайденнаяСтрока = ТЗ.Найти(Артикул, "Артикул");
Если НайденнаяСтрока = Неопределено Тогда
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Артикул = Артикул;
НоваяСтрока.Количество = Количество;
Иначе
НайденнаяСтрока.Количество = НайденнаяСтрока.Количество + Количество;
КонецЕсли;
Найденная строка — не копия, а сама строка таблицы. Если поменять в ней поле, изменится таблица.
Что важно знать про Найти
- ☝️ Метод возвращает только первое совпадение. Продолжить поиск «со следующей строки» он не умеет: для повторов нужен
НайтиСтроки. - 🧩 Если перечислить несколько колонок (
"Код, Артикул"), строка найдётся, когда значение совпадёт хотя бы в одной из них. Это не поиск по двум условиям сразу. - 🔢 Номер найденной строки даёт
ТЗ.Индекс(НайденнаяСтрока). Нумерация с нуля.
Поиск без параметра Колонки идёт по всем колонкам. Число 1 может совпасть с колонкой «Количество», хотя вы искали код. Всегда указывайте колонку явно.
НайтиСтроки: все строки по одному или нескольким условиям
Когда нужно вытащить все строки, где совпадают значения сразу в нескольких колонках, берите НайтиСтроки. Условия задаются структурой: ключ — имя колонки, значение — что ищем.
Отбор = Новый Структура;
Отбор.Вставить("Склад", СкладОсновной);
Отбор.Вставить("Организация", Организация);
НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
Строка.Цена = НоваяЦена;
КонецЦикла;
Условия в структуре соединяются через «И»: строка попадёт в результат, только если совпали все поля. Если ничего не нашлось, вернётся пустой массив, а не Неопределено. Проверка — НайденныеСтроки.Количество() = 0.
Удаление найденных строк
Массив из НайтиСтроки — отдельная коллекция. Поэтому по нему можно идти циклом и удалять строки из таблицы без риска пропустить соседние:
ПустыеСтроки = ТЗ.НайтиСтроки(Новый Структура("Количество", 0));
Для Каждого Строка Из ПустыеСтроки Цикл
ТЗ.Удалить(Строка);
КонецЦикла;
Если же удалять прямо в цикле Для Каждого ... Из ТЗ, строки будут пропускаться. Там нужен обратный цикл по индексу.
Ключи структуры должны точно совпадать с именами колонок. Опечатка в ключе даёт ошибку выполнения, а не пустой результат.
Отбор и сортировка: новая таблица только с нужными строками
Иногда нужна не ссылка на строки, а отдельная таблица с отобранными данными: передать в другую процедуру, вывести в отчёт, посчитать итог. Для этого у метода Скопировать есть параметр отбора.
Отбор = Новый Структура("Склад", СкладОсновной);
ТЗСклада = ТЗ.Скопировать(Отбор, "Номенклатура, Количество, Сумма");
ТЗСклада.Сортировать("Сумма Убыв");
ИтогПоСкладу = ТЗСклада.Итог("Сумма");
Здесь три шага в одном фрагменте:
Скопировать(Отбор, Колонки)создаёт новую таблицу со строками, прошедшими отбор, и только с перечисленными колонками.Сортировать("Сумма Убыв")упорядочивает строки. Можно указать несколько колонок:"Склад, Сумма Убыв". Без словаУбывсортировка по возрастанию.Итог("Сумма")возвращает сумму числовой колонки.
Изменения в копии на исходную таблицу не влияют. Это и плюс, и ловушка: если нужно править исходные данные, берите НайтиСтроки.
Найти максимум или минимум
Отдельного метода «найти максимальное значение» нет. Рабочий приём — отсортировать и взять первую строку:
Копия = ТЗ.Скопировать();
Копия.Сортировать("Сумма Убыв");
Если Копия.Количество() > 0 Тогда
СтрокаМакс = Копия[0];
КонецЕсли;
Сортировать копию стоит, если порядок исходной таблицы важен, например, она выведена на форму. Для больших таблиц быстрее один проход циклом с запоминанием текущего максимума.
Когда условие не «равно»
Найти и НайтиСтроки проверяют только равенство. Условия «больше», «не равно», «содержит подстроку» решаются циклом или запросом:
Результат = Новый Массив;
Для Каждого Строка Из ТЗ Цикл
Если Строка.Сумма > 10000 И СтрНайти(Строка.Комментарий, "срочно") > 0 Тогда
Результат.Добавить(Строка);
КонецЕсли;
КонецЦикла;
СтрНайти есть в платформе начиная с 8.3.6. Он учитывает регистр, поэтому «Срочно» и «срочно» для него разные строки.
Поиск в таблице значений запросом
Когда условий много, нужна группировка или соединение со справочником, проще передать таблицу в запрос. Схема всегда одна: таблицу передают параметром и сначала помещают во временную таблицу.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура,
| Т.Количество КАК Количество,
| Т.Сумма КАК Сумма
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &ТаблицаДанных КАК Т
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ.Номенклатура КАК Номенклатура,
| СУММА(ВТ.Количество) КАК Количество
|ИЗ
| ВТ_Данные КАК ВТ
|ГДЕ
| ВТ.Сумма > &Порог
| И ВТ.Номенклатура.Наименование ПОДОБНО &Шаблон
|
|СГРУППИРОВАТЬ ПО
| ВТ.Номенклатура";
Запрос.УстановитьПараметр("ТаблицаДанных", ТЗ);
Запрос.УстановитьПараметр("Порог", 10000);
Запрос.УстановитьПараметр("Шаблон", "%кабель%");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Выборка.Номенклатура, Выборка.Количество
КонецЦикла;
Что даёт запрос по сравнению с циклом:
- 🔗 обращение к реквизитам ссылок через точку (
ВТ.Номенклатура.Наименование); - 🧮 группировки, итоги,
РАЗЛИЧНЫЕ; - 🔤 поиск по шаблону через
ПОДОБНО; - 🤝 соединение с таблицами базы — например, отобрать только товары с остатком.
Требование к типам колонок
Колонки таблицы, которую вы передаёте в запрос, должны иметь описание типов. Если таблица собрана через Колонки.Добавить("Сумма") без второго параметра, запрос выдаст ошибку при выполнении. Создавайте колонки так:
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
ТЗ.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
Таблица, полученная из результата другого запроса (Выгрузить()), уже типизирована, с ней проблем нет.
Запрос к таблице значений имеет смысл, когда нужна его логика. Для одного поиска по равенству он медленнее НайтиСтроки: данные копируются во временную таблицу.
Сравнение значений: почему строка «есть», а Найти её не видит
Большая часть вопросов «Найти возвращает Неопределено, хотя строка точно есть» сводится к сравнению. Платформа сравнивает значение вместе с типом и без приведений.
| Что ищете | Что в колонке | Найдётся? | Как исправить |
|---|---|---|---|
"100" (строка) | 100 (число) | ❌ | привести тип: Число("100") |
"Иванов" | "Иванов " (пробел в конце) | ❌ | СокрЛП при заполнении колонки |
"иванов" | "Иванов" | ❌ | цикл со сравнением ВРег |
10 | 10.00 | ✅ | — |
'20260107' (дата без времени) | '20260107153000' | ❌ | хранить НачалоДня(Дата) |
Неопределено | пустая ссылка справочника | ❌ | искать пустую ссылку: Справочники.Номенклатура.ПустаяСсылка() |
| ссылка на элемент | та же ссылка | ✅ | — |
Ловушка квалификаторов
Значение, записанное в типизированную колонку, приводится к её типу. Если колонка объявлена как строка длиной 10, а вы записали "Поставщик_001", в таблице окажется "Поставщик_". Поиск полной строкой ничего не найдёт. То же с числами: при точности 2 знака значение 1.005 будет сохранено округлённым.
Если у колонки составной тип или тип не задан, в ней могут соседствовать строка "5" и число 5. Поиск найдёт только значение того же типа, что вы передали.
Поиск без учёта регистра
Готового параметра нет. Решение — цикл с приведением к верхнему регистру:
Функция НайтиБезУчетаРегистра(ТЗ, ИмяКолонки, Текст)
Искомое = ВРег(СокрЛП(Текст));
Для Каждого Строка Из ТЗ Цикл
Если ВРег(СокрЛП(Строка[ИмяКолонки])) = Искомое Тогда
Возврат Строка;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
Функция рассчитана на строковую колонку. Если поиск по тексту нужен часто, заведите в таблице служебную колонку с уже приведённым значением и ищите по ней обычным Найти.
Как ускорить поиск: индексы и соответствие
Найти и НайтиСтроки без индекса просматривают таблицу целиком. На таблице в 500 строк этого не видно. Но поиск внутри цикла по другой коллекции — частый сценарий: 50 000 строк документа × 50 000 строк таблицы дают 2,5 млрд сравнений. Обработка, которая должна работать секунды, идёт десятки минут.
Индекс таблицы значений
ТЗ.Индексы.Добавить("Склад, Номенклатура");
Отбор = Новый Структура("Склад, Номенклатура");
Для Каждого СтрокаДокумента Из СтрокиДокумента Цикл
Отбор.Склад = СтрокаДокумента.Склад;
Отбор.Номенклатура = СтрокаДокумента.Номенклатура;
Найденные = ТЗ.НайтиСтроки(Отбор);
// ...
КонецЦикла;
Правила, при которых индекс реально работает:
- Набор колонок в индексе совпадает с ключами структуры в
НайтиСтроки. - Индекс добавлен один раз, до цикла поиска, а не на каждой итерации.
- Индексированные колонки не меняются массово во время поиска: каждое изменение пересчитывает индекс.
Структуру Отбор удобно создать один раз и только менять значения: так не плодятся лишние объекты в цикле.
Соответствие вместо таблицы
Если ключ уникален (артикул, код, ссылка), самый быстрый вариант — один раз построить Соответствие:
КартаАртикулов = Новый Соответствие;
Для Каждого Строка Из ТЗ Цикл
КартаАртикулов.Вставить(Строка.Артикул, Строка);
КонецЦикла;
НайденнаяСтрока = КартаАртикулов.Получить(Артикул); // Неопределено, если нет
При повторяющихся артикулах в соответствии останется последняя строка с этим ключом. Если дубли важны, храните в значении массив строк.
Какой способ выбрать
| Задача | Способ | Скорость на больших таблицах |
|---|---|---|
| Одна строка, один раз | Найти | нормально |
| Все строки по равенству | НайтиСтроки | нормально, с индексом — быстро |
| Много поисков в цикле | НайтиСтроки + индекс или Соответствие | быстро |
| Отдельная таблица с отбором | Скопировать(Отбор) | нормально |
| «Больше/меньше», подстрока | цикл или запрос | зависит от объёма |
| Группировка, связь с базой | запрос | быстро на сложной логике |
Таблица значений на управляемой форме
На форме таблица значений живёт в виде реквизита. В клиентском коде это уже не ТаблицаЗначений, а коллекция данных формы. У неё есть НайтиСтроки, но нет метода Найти. Поэтому код с Объект.Товары.Найти(...) в клиентской процедуре формы падает, а тот же код на сервере с табличной частью объекта работает.
Варианты решения:
- 🖥️ на клиенте использовать
НайтиСтрокисо структурой и брать первый элемент массива; - ⚙️ перенести поиск в серверную процедуру и получить таблицу через
РеквизитФормыВЗначение("ИмяРеквизита"), а после правок вернуть её методомЗначениеВРеквизитФормы.
Второй вариант нужен, когда требуются индексы, Скопировать или запрос: на клиенте их нет. Не вызывайте сервер из цикла по строкам — один вызов на всю операцию.
Частые ошибки при поиске
- ❌ Проверка результата
НайтиСтрокинаНеопределено. Метод всегда возвращает массив. УсловиеЕсли Найденные = Неопределеноникогда не сработает, и код дальше обратится кНайденные[0]на пустом массиве. - ❌ Обращение к полю без проверки.
ТЗ.Найти(Код, "Код").Наименованиеупадёт с ошибкой, если строки нет: уНеопределенополей не бывает. Сначала сохраните результат в переменную и проверьте. - ❌ Ожидание поиска «по всем условиям» от
Найти. Перечисление колонок через запятую — это «в любой из колонок», а не «во всех сразу». - ❌ Удаление строк в прямом цикле по таблице. После удаления индексы сдвигаются, и следующая строка пропускается.
- ❌ Пересоздание индекса внутри цикла. Вызов
Индексы.Добавитьна каждой итерации делает поиск медленнее, чем без индекса.
Частые вопросы
Как проверить, есть ли значение в колонке, не получая строку?
Найти с Неопределено: Есть = ТЗ.Найти(Значение, "Колонка") <> Неопределено. Отдельного метода «Содержит» у таблицы значений нет.Как найти строки, где значение входит в список из нескольких вариантов?
НайтиСтроки принимает одно значение на колонку. Для списка вызовите его для каждого варианта и объедините массивы либо используйте запрос с условием В (&Список).Можно ли выгрузить колонку и искать в массиве?
ТЗ.ВыгрузитьКолонку("Артикул") вернёт массив, а Массив.Найти(Значение) — индекс элемента или Неопределено. Индекс совпадает с индексом строки в таблице, пока таблицу не сортировали и не меняли.Ищет ли НайтиСтроки по колонке со ссылкой на документ?
Чем поиск в таблице значений отличается от поиска в табличной части документа?
Найти и НайтиСтроки с тем же поведением. Но индексы и Скопировать с отбором — возможности именно таблицы значений: для них табличную часть выгружают методом Выгрузить().