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