Поиск нужной позиции в 1С: от строки поиска до запроса и СКД

· 10 мин

Содержание

Чтобы найти позицию в 1С 8.3, откройте список (например, справочник номенклатуры), нажмите Ctrl+F и введите часть наименования, кода или артикула. Если нужно искать по конкретному полю — Alt+F открывает расширенный поиск с выбором колонки и вида сравнения. Сброс поиска — Ctrl+Q.

Это работает для пользователя. Разработчику нужны другие инструменты: запрос с условием ПОДОБНО, отбор в системе компоновки данных, методы НайтиПоКоду() и НайтиПоРеквизиту(). От выбранного способа зависит скорость: поиск по индексированному полю отрабатывает за доли секунды даже на сотнях тысяч строк, поиск по подстроке — заметно дольше.

Как найти позицию в списке: строка поиска, расширенный поиск, отбор

В интерфейсе «Такси» у любой формы списка есть три механизма поиска. Они дают разный результат, и их часто путают.

СпособКак вызватьЧто делаетКогда удобен
Строка поискаCtrl+F или поле «Поиск» над спискомИщет введённую строку во всех видимых колонкахПомните кусок названия или артикула
Расширенный поискAlt+F или Ещё → Расширенный поискИщет в одной выбранной колонке с видом сравненияНужно точное совпадение кода или поиск только по артикулу
ОтборНастройки списка в меню «Ещё», вкладка «Отбор»Оставляет в списке только строки по условиямНужно несколько условий сразу или сохранить настройку

Строка поиска

  1. Откройте список, например справочник «Номенклатура».
  2. Нажмите Ctrl+F — курсор встанет в поле поиска.
  3. Введите фрагмент: болт м8, 00-00012, часть артикула.
  4. Список сократится до совпадений. Чтобы вернуть всё, нажмите 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 нужной позиции в другом узле можно кодом: Ссылка.УникальныйИдентификатор().

Позиция не дошла до узла

Если позиция есть в центре, но не находится в периферийной базе, проверьте, зарегистрирована ли она к выгрузке. Таблица изменений доступна в запросе:

"ВЫБРАТЬ
|    Изменения.Узел,
|    Изменения.НомерСообщения
|ИЗ
|    Справочник.Номенклатура.Изменения КАК Изменения
|ГДЕ
|    Изменения.Ссылка = &Позиция"

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

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

Почему строка поиска не находит позицию, которая точно есть в справочнике?
Чаще всего поиск идёт внутри открытой группы иерархического справочника или искомого поля нет среди колонок списка. Переключите режим просмотра на список и выведите нужную колонку.
Как найти позицию по штрихкоду?
В торговых конфигурациях, например в УТ 11, штрихкоды хранятся в отдельном регистре сведений «Штрихкоды номенклатуры», а не в карточке товара. Удобнее всего отсканировать код сканером в форме документа или найти регистр по слову «штрихкод» в разделе «Все функции».
Можно ли искать в 1С без учёта регистра букв?
Строка поиска в списке регистр не различает. А вот Найти() и НайтиСтроки() у таблицы значений сравнивают строки как есть: «Болт» и «болт» для них разные значения. Перед поиском в памяти приводите строки к одному виду через ВРег().
Как найти позиции с одинаковым наименованием?
Запросом с группировкой: ВЫБРАТЬ Наименование, КОЛИЧЕСТВО(Ссылка) ... СГРУППИРОВАТЬ ПО Наименование ИМЕЮЩИЕ КОЛИЧЕСТВО(Ссылка) > 1. Это быстрее и надёжнее, чем просматривать список глазами.