Поиск нужной позиции в 1С: от строки поиска до запроса и СКД
Содержание
Чтобы найти позицию в 1С 8.3, откройте список (например, справочник номенклатуры), нажмите Ctrl+F и введите часть наименования, кода или артикула. Если нужно искать по конкретному полю — Alt+F открывает расширенный поиск с выбором колонки и вида сравнения. Сброс поиска — Ctrl+Q.
Это работает для пользователя. Разработчику нужны другие инструменты: запрос с условием ПОДОБНО, отбор в системе компоновки данных, методы НайтиПоКоду() и НайтиПоРеквизиту(). От выбранного способа зависит скорость: поиск по индексированному полю отрабатывает за доли секунды даже на сотнях тысяч строк, поиск по подстроке — заметно дольше.
Как найти позицию в списке: строка поиска, расширенный поиск, отбор
В интерфейсе «Такси» у любой формы списка есть три механизма поиска. Они дают разный результат, и их часто путают.
| Способ | Как вызвать | Что делает | Когда удобен |
|---|---|---|---|
| Строка поиска | Ctrl+F или поле «Поиск» над списком | Ищет введённую строку во всех видимых колонках | Помните кусок названия или артикула |
| Расширенный поиск | Alt+F или Ещё → Расширенный поиск | Ищет в одной выбранной колонке с видом сравнения | Нужно точное совпадение кода или поиск только по артикулу |
| Отбор | Настройки списка в меню «Ещё», вкладка «Отбор» | Оставляет в списке только строки по условиям | Нужно несколько условий сразу или сохранить настройку |
Строка поиска
- Откройте список, например справочник «Номенклатура».
- Нажмите
Ctrl+F— курсор встанет в поле поиска. - Введите фрагмент:
болт м8,00-00012, часть артикула. - Список сократится до совпадений. Чтобы вернуть всё, нажмите
Ctrl+Qили крестик в поле.
💡 Строка поиска смотрит только на колонки, которые сейчас выведены в список. Если артикула нет среди колонок, по артикулу она не найдёт. Добавьте колонку через Ещё → Изменить форму — и поиск начнёт её учитывать.
Расширенный поиск
Окно Alt+F полезно, когда простой поиск выдаёт слишком много. Встаньте курсором в нужную колонку (например, «Код»), нажмите Alt+F — поле подставится само. Дальше выберите вариант совпадения: по части строки, по началу или точное. Точное совпадение по коду возвращает одну строку и работает быстрее всего.
Иерархический справочник
В иерархических справочниках поиск по умолчанию идёт внутри открытой группы. Если позиция лежит в другой папке, её «не видно». Переключите отображение на список (Ещё → Режим просмотра → Список) — тогда поиск охватит весь справочник, а найденная позиция покажет свою группу в колонке.
Где используется позиция
Найти сам элемент мало, иногда нужно понять, в каких документах он участвует. Для этого есть стандартная обработка «Поиск ссылок на объект»: Все функции → Стандартные → Поиск ссылок на объект. Если пункта «Все функции» нет в главном меню, включите его в Сервис и настройки → Параметры, флажок «Отображать команду “Все функции”». В типовых конфигурациях на БСП в карточке есть также команда «Места использования» в меню «Ещё».
Полнотекстовый поиск по всей базе
Когда непонятно, в каком справочнике или документе лежит нужная строка, помогает полнотекстовый поиск. Он ищет слово сразу по всем объектам, включённым в индекс.
Включается он в типовых конфигурациях в Администрирование → Общие настройки, блок «Полнотекстовый поиск». Там же видна дата актуальности индекса и кнопка ручного обновления. Искать можно через поле поиска в заголовке окна программы.
Полезные операторы:
- 🔤
болт*— все слова, начинающиеся с «болт»; - 📎
"болт м8"в кавычках — точная фраза; - ➕
болт И оцинк*— оба слова в одном объекте; - ➖
болт НЕ м10— исключить лишнее; - 🔍
#болд— нечёткий поиск, найдёт и слово с опечаткой.
Свежие записи попадают в индекс не сразу, а после очередного обновления. Его выполняют регламентные задания «Обновление индекса ППД» и «Слияние индекса ППД». В файловой базе регламентные задания работают только при открытом сеансе пользователя, поэтому индекс может отставать на часы. Если позиция создана сегодня и не находится — сначала обновите индекс.
Программно то же самое делается так:
Список = ПолнотекстовыйПоиск.СоздатьСписок("болт* И оцинк*", 50);
Список.ПерваяЧасть();
Для Каждого Элемент Из Список Цикл
Сообщить(Строка(Элемент.Значение) + " — " + Элемент.Описание);
КонецЦикла;
Поиск позиции запросом на языке 1С
В коде основной способ найти позицию — запрос. Точное совпадение по коду:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Код = &Код
| И НЕ Номенклатура.ПометкаУдаления";
Запрос.УстановитьПараметр("Код", "00-00012");
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
НайденнаяПозиция = Выборка.Ссылка;
КонецЕсли;
Поиск по части строки
Для поиска по фрагменту используется ПОДОБНО с шаблоном:
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ ""~""";
Запрос.УстановитьПараметр("Шаблон", "%" + ЭкранироватьШаблон(СтрокаПоиска) + "%");
Символы %, _, [, ] и ^ внутри шаблона служебные. Если пользователь ищет «скидка 10%», знак процента сработает как маска, и результат будет неверным. Поэтому служебные символы экранируют:
Функция ЭкранироватьШаблон(Знач Текст)
Для Каждого Символ Из СтрРазделить("~,%,_,[,],^", ",") Цикл
Текст = СтрЗаменить(Текст, Символ, "~" + Символ);
КонецЦикла;
Возврат Текст;
КонецФункции
Тильда экранируется первой — иначе она задвоится в уже обработанных символах.
Строки неограниченной длины
Реквизит вроде «Описание» или «Комментарий» часто объявлен строкой неограниченной длины. Сравнивать его через = в запросе нельзя, получите ошибку. Приведите тип:
"ГДЕ ВЫРАЗИТЬ(Номенклатура.Описание КАК СТРОКА(200)) = &Текст"
ПОДОБНО с такими полями работает без приведения, но индекс по ним не строится, и поиск всегда идёт полным просмотром таблицы.
Отбор в системе компоновки данных (СКД)
В отчётах на СКД позицию находят через отбор. Пользователь делает это кнопкой «Настройки» в форме отчёта: добавляет поле «Номенклатура» и выбирает вид сравнения — «Равно», «В списке», «В группе», «Содержит».
Разработчику важно знать, куда отбор попадает. Если поле доступно в основном запросе набора данных, СКД переносит условие прямо в текст запроса, и база отдаёт уже отфильтрованные строки. Если поле вычисляемое или появилось только в ресурсах, фильтрация пойдёт после выборки — по всем данным.
Добавить отбор программно:
Отбор = КомпоновщикНастроек.Настройки.Отбор;
ЭлементОтбора = Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = НайденнаяПозиция;
ЭлементОтбора.Использование = Истина;
💡 Вид сравнения «Содержит» превращается в ПОДОБНО "%...%", а «Равно» — в обычное равенство. На больших регистрах разница во времени формирования отчёта бывает десятикратной. Если пользователь знает позицию точно, пусть выбирает её из справочника, а не вводит текст.
Для оборотных и остаточных регистров есть приём сильнее: отбор по позиции передают в параметры виртуальной таблицы — Остатки(&Период, Номенклатура = &Номенклатура). Так условие применяется до расчёта итогов, а не после.
Программный поиск: методы менеджеров и коллекций
Когда нужна одна позиция по известному признаку, запрос не обязателен. Менеджеры справочников умеют искать сами.
| Метод | Пример | Особенность |
|---|---|---|
НайтиПоКоду() | Справочники.Номенклатура.НайтиПоКоду("00-00012") | Для иерархии с кодами внутри группы есть параметр поиска по полному коду |
НайтиПоНаименованию() | Справочники.Номенклатура.НайтиПоНаименованию("Болт М8", Истина) | Второй параметр — точное совпадение; без него ищет по началу строки |
НайтиПоРеквизиту() | Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", "BM8-40") | Не работает с реквизитами неограниченной длины |
НайтиПоНомеру() | Документы.ПоступлениеТоваровУслуг.НайтиПоНомеру("0000-000123", ТекущаяДата()) | Номер уникален в пределах периода, поэтому нужна дата |
Все методы возвращают пустую ссылку, если ничего не найдено. Проверяйте результат через .Пустая(), а не через Неопределено.
Если подходящих элементов несколько, метод вернёт любой из них, без гарантии какого именно. Для наименований, где дубли — обычное дело, это частая причина «подставилась не та позиция». В таких случаях используйте запрос и проверяйте количество найденных строк.
Поиск в коллекциях
Когда данные уже в памяти, база не нужна:
- 📋
ТаблицаЗначений.Найти(Значение, "Колонка")— первая строка илиНеопределено; - 📋
ТаблицаЗначений.НайтиСтроки(Новый Структура("Номенклатура, Склад", Позиция, Склад))— массив всех совпавших строк; - 📋
Массив.Найти(Значение)— индекс элемента илиНеопределено; - 📋
СписокЗначений.НайтиПоЗначению(Значение)— элемент списка.
Если по таблице значений ищут в цикле тысячи раз, добавьте индекс: Таблица.Индексы.Добавить("Номенклатура, Склад"). НайтиСтроки() с той же структурой полей начнёт использовать его, и время сократится в разы.
Поставить курсор на найденную позицию
Частая задача в форме — не просто найти, а показать пользователю. В динамическом списке:
Элементы.Список.ТекущаяСтрока = НайденнаяПозиция;
В табличной части документа на управляемой форме текущую строку задают идентификатором:
Строки = Объект.Товары.НайтиСтроки(Новый Структура("Номенклатура", НайденнаяПозиция));
Если Строки.Количество() > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Строки[0].ПолучитьИдентификатор();
КонецЕсли;
Чтобы отфильтровать динамический список кодом в типовой конфигурации, удобна процедура БСП ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(): она сама найдёт или создаст элемент отбора.
Индексы и скорость поиска позиций
Поиск быстрый, когда база может пройти по индексу, а не читать таблицу целиком. Код и наименование справочника платформа индексирует сама. Для остальных реквизитов индекс задаётся в конфигураторе, свойство реквизита «Индексировать»:
- ⚙️ «Не индексировать» — значение по умолчанию;
- ⚙️ «Индексировать» — индекс по одному полю, для поиска по равенству;
- ⚙️ «Индексировать с доп. упорядочиванием» — индекс дополнительно включает поле упорядочивания (код или наименование), подходит для форм списка с сортировкой.
Что ломает индекс в запросе:
- ❌ шаблон с ведущим
%—ПОДОБНО "%болт%"всегда читает всю таблицу;ПОДОБНО "болт%"в клиент-серверной базе может пойти по индексу; - ❌ функция над полем в условии —
ПОДСТРОКА(Наименование, 1, 4) = "Болт"илиВЫРАЗИТЬ(...); - ❌ условие
ИЛИпо разным полям — часто дешевле разбить на два запроса и объединить; - ❌ условие на поле через точку от составного типа —
Регистратор.Контрагентпорождает соединения со всеми таблицами типов.
💡 Если поиск по артикулу — ежедневная операция и справочник растёт, индекс по реквизиту «Артикул» окупается сразу. Цена — немного больше места в базе и чуть медленнее запись элементов.
Изменение свойства «Индексировать» требует обновления конфигурации базы данных с реструктуризацией таблицы. На большом справочнике это занимает время и требует монопольного доступа, планируйте такое обновление на нерабочее время и сделайте резервную копию перед ним.
Поиск позиции в распределённой информационной базе (РИБ)
В РИБ одна и та же позиция существует в нескольких узлах. Это добавляет две проблемы.
Код не уникален между узлами
Новые элементы в разных узлах нумеруются независимо. Чтобы коды не совпадали, в каждом узле задают префикс: в типовых конфигурациях это настройка «Префикс этой информационной базы» в разделе Администрирование → Синхронизация данных. Если префиксы не заданы или одинаковы, НайтиПоКоду() в центральной базе может вернуть позицию, созданную в другом магазине.
Надёжный ключ — уникальный идентификатор
Ссылка на объект во всех узлах одинаковая, её основа — уникальный идентификатор (GUID). По нему позицию находят однозначно:
ИД = Новый УникальныйИдентификатор("1f2e3d4c-5b6a-7980-1a2b-3c4d5e6f7a8b");
Ссылка = Справочники.Номенклатура.ПолучитьСсылку(ИД);
Если Ссылка.ПолучитьОбъект() = Неопределено Тогда
// в этом узле позиции ещё нет: не пришла выгрузка
КонецЕсли;
ПолучитьСсылку() вернёт ссылку всегда, даже на несуществующий объект. Проверка через ПолучитьОбъект() обязательна. Получить GUID нужной позиции в другом узле можно кодом: Ссылка.УникальныйИдентификатор().
Позиция не дошла до узла
Если позиция есть в центре, но не находится в периферийной базе, проверьте, зарегистрирована ли она к выгрузке. Таблица изменений доступна в запросе:
"ВЫБРАТЬ
| Изменения.Узел,
| Изменения.НомерСообщения
|ИЗ
| Справочник.Номенклатура.Изменения КАК Изменения
|ГДЕ
| Изменения.Ссылка = &Позиция"
Нет строки для нужного узла — позиция не попадёт в следующий обмен, её нужно зарегистрировать заново. Строка есть с заполненным номером сообщения — выгрузка ушла, но узел её ещё не подтвердил: смотрите на загрузку в периферийной базе.
Частые вопросы
Почему строка поиска не находит позицию, которая точно есть в справочнике?
Как найти позицию по штрихкоду?
Можно ли искать в 1С без учёта регистра букв?
Найти() и НайтиСтроки() у таблицы значений сравнивают строки как есть: «Болт» и «болт» для них разные значения. Перед поиском в памяти приводите строки к одному виду через ВРег().Как найти позиции с одинаковым наименованием?
ВЫБРАТЬ Наименование, КОЛИЧЕСТВО(Ссылка) ... СГРУППИРОВАТЬ ПО Наименование ИМЕЮЩИЕ КОЛИЧЕСТВО(Ссылка) > 1. Это быстрее и надёжнее, чем просматривать список глазами.