Как реализовать побуквенный динамический поиск в справочнике 1С 7.7

Программист 1С v7.7 Управленческий учет IT и автоматизация бизнеса
← На главную

В современных интерфейсах, особенно при работе на Терминалах Сбора Данных (ТСД) или сенсорных мониторах, стандартный механизм поиска 1С 7.7 часто оказывается недостаточно гибким. Типовой поиск по первым буквам в списке требует активации строки и не позволяет удобно фильтровать данные «на лету» в отдельном поле ввода. В этой статье мы разберем, как создать механизм динамического поиска, который при вводе каждого символа будет мгновенно обновлять список найденных товаров, используя мощь прямых SQL-запросов.

Проблема штатных средств поиска

Стандартный метод НайтиПоНаименованию() работает достаточно быстро только для одиночного поиска. Однако, если мы попытаемся реализовать поиск внутри цикла ВыбратьЭлементы(), чтобы заполнить таблицу значений (ТЗ) подходящими элементами, мы столкнемся с резким падением производительности. Более того, метод НайтиПоНаименованию сбивает текущую выборку справочника. Рассмотрим, почему прямой перебор — это плохая идея:


// Пример медленного поиска (не рекомендуется)
Спр = СоздатьОбъект("Справочник.Товары");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
    // Каждая проверка Найти() на больших базах будет «вешать» интерфейс
    Если Найти(Спр.Наименование, ПолеПоиска) > 0 Тогда
        // Добавление в таблицу...
    КонецЕсли;
КонецЦикла;

Чтобы интерфейс не «фризил» при вводе каждой буквы, нам необходимо использовать внешние компоненты, такие как 1sqlite или 1C++.

Шаг 1: Подключение компоненты 1sqlite

Для файловых баз 1С 7.7 идеальным решением является компонента 1sqlite.dll. Она позволяет работать с DBF-файлами через SQL-запросы, что в десятки и сотни раз быстрее обычного перебора объектов. Разберем процесс инициализации базы в памяти:


Попытка
    База = СоздатьОбъект("SQLiteBase");
Исключение
    ЗагрузитьВнешнююКомпоненту("1sqlite.dll");
    База = СоздатьОбъект("SQLiteBase");
КонецПопытки;

// Открываем базу в оперативной памяти для максимальной скорости
База.Открыть(":memory:");
Запрос = База.НовыйЗапрос();

Шаг 2: Реализация базового SQL-поиска

Теперь сформулируем запрос, который будет искать товары, наименование которых начинается с введенных пользователем символов. Мы будем использовать оператор LIKE. Выясним важный нюанс: в именах таблиц 1С 7.7 для 1sqlite нужно использовать квадратные скобки.


Процедура ПоискПоБукв()
    ТекстЗапроса = "
    |SELECT id [Товар :Справочник.Товары]
    |FROM [Справочник.Товары]
    |WHERE descr LIKE '" + СокрЛП(ПолеПоиска) + "%'
    |AND isfolder = 2
    |AND ismark = 0";
    
    // Выполняем запрос и загружаем результат в таблицу значений на форме
    ТЗ = Запрос.ВыполнитьЗапрос(ТекстЗапроса);
    ТабВиб.Загрузить(ТЗ);
КонецПроцедуры

Разберем параметры запроса подробнее:

Шаг 3: Оптимизация поиска и вывод остатков

Зачастую просто найти товар недостаточно — пользователю на ТСД нужно сразу видеть актуальный остаток. Выполнять запрос остатка для каждого найденного товара отдельно (в цикле) — это архитектурная ошибка. Правильнее объединить (JOIN) таблицу справочника с таблицей итогов бухгалтерского учета или регистров.

Рассмотрим пример запроса к бухгалтерским итогам (таблица _1SBKTTL), если остатки хранятся на счете 28.1 (товары на складе):


// Получаем начало текущего квартала для корректного обращения к итогам
МД = СоздатьОбъект("MetaDataWork");
НачПериод = МД.ПолучитьНачПериода(ТекущаяДата());
Запрос.Подставлять("НачПериод", НачПериод);
Запрос.Подставлять("Счет", СчетПоКоду("28.1"));

ТекстЗапроса = "
|SELECT
|  Остатки.SC1 [Товар :Справочник.Товары],
|  Остатки.SD КоличествоОстаток
|FROM [_1S.BKTTL] AS Остатки
|INNER JOIN [Справочник.Товары] AS Спр ON Спр.id = Остатки.SC1
|WHERE Остатки.ACCID = :Счет
|  AND Остатки.DATE = :НачПериод
|  AND Спр.descr LIKE '" + СокрЛП(ПолеПоиска) + "%'
|  AND Остатки.SD <> 0";

Важно: Поле SC1 (или SC0, SC2) соответствует номеру субконто на счете. Если «Номенклатура» является вторым субконто, используйте SC1. Если первым — SC0.

Шаг 4: Продвинутые техники интерфейса

Чтобы сделать поиск по-настоящему «летающим», воспользуемся дополнительными приемами из практики разработки на 1С 7.7:

  1. Использование компоненты FormEx: Для того чтобы процедура ПоискПоБукв() вызывалась автоматически при каждом нажатии клавиши, нужно перехватывать событие клавиатуры. В FormEx это делается через метод ПриНажатииКлавиши. Без этого пользователю придется нажимать Enter или переходить между полями, что убивает идею динамического подбора.
  2. Таймер (Debounce): Если база данных очень большая, выполнение запроса на каждую букву может замедлять ввод. Проанализируем ситуацию: пользователь может печатать быстро. В таком случае логично запускать поиск через 300-500 миллисекунд после последнего нажатия. Это реализуется через Сервис.ВключитьТаймер() в FormEx.
  3. Виртуальные списки: Для экстремальной производительности вместо обычной ТЗ можно использовать TableEx. Это позволяет отрисовывать данные напрямую из SQL-выборки, не нагружая память 1С хранением тысяч строк в объекте ТаблицаЗначений.

Рекомендации по индексам

Для того чтобы SQL-запрос работал мгновенно, убедитесь, что в конфигураторе для справочника включена «Сортировка по наименованию». Это создает индекс в файле .cdx, который компонента 1sqlite будет использовать для ускорения оператора LIKE. Если вы используете поиск по вхождению в середине строки (LIKE '%текст%'), помните, что индексы в этом случае не работают, и на справочниках более 50 000 элементов возможны задержки.

Использование связки 1sqlite + прямые запросы превращает старую добрую «семерку» в современный инструмент, способный конкурировать с восьмой платформой по скорости отклика интерфейса в задачах складского учета и оперативного подбора товаров.

← На главную