В современных интерфейсах, особенно при работе на Терминалах Сбора Данных (ТСД) или сенсорных мониторах, стандартный механизм поиска 1С 7.7 часто оказывается недостаточно гибким. Типовой поиск по первым буквам в списке требует активации строки и не позволяет удобно фильтровать данные «на лету» в отдельном поле ввода. В этой статье мы разберем, как создать механизм динамического поиска, который при вводе каждого символа будет мгновенно обновлять список найденных товаров, используя мощь прямых SQL-запросов.
Стандартный метод НайтиПоНаименованию() работает достаточно быстро только для одиночного поиска. Однако, если мы попытаемся реализовать поиск внутри цикла ВыбратьЭлементы(), чтобы заполнить таблицу значений (ТЗ) подходящими элементами, мы столкнемся с резким падением производительности. Более того, метод НайтиПоНаименованию сбивает текущую выборку справочника. Рассмотрим, почему прямой перебор — это плохая идея:
// Пример медленного поиска (не рекомендуется)
Спр = СоздатьОбъект("Справочник.Товары");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
// Каждая проверка Найти() на больших базах будет «вешать» интерфейс
Если Найти(Спр.Наименование, ПолеПоиска) > 0 Тогда
// Добавление в таблицу...
КонецЕсли;
КонецЦикла;
Чтобы интерфейс не «фризил» при вводе каждой буквы, нам необходимо использовать внешние компоненты, такие как 1sqlite или 1C++.
Для файловых баз 1С 7.7 идеальным решением является компонента 1sqlite.dll. Она позволяет работать с DBF-файлами через SQL-запросы, что в десятки и сотни раз быстрее обычного перебора объектов. Разберем процесс инициализации базы в памяти:
Попытка
База = СоздатьОбъект("SQLiteBase");
Исключение
ЗагрузитьВнешнююКомпоненту("1sqlite.dll");
База = СоздатьОбъект("SQLiteBase");
КонецПопытки;
// Открываем базу в оперативной памяти для максимальной скорости
База.Открыть(":memory:");
Запрос = База.НовыйЗапрос();
Теперь сформулируем запрос, который будет искать товары, наименование которых начинается с введенных пользователем символов. Мы будем использовать оператор LIKE. Выясним важный нюанс: в именах таблиц 1С 7.7 для 1sqlite нужно использовать квадратные скобки.
Процедура ПоискПоБукв()
ТекстЗапроса = "
|SELECT id [Товар :Справочник.Товары]
|FROM [Справочник.Товары]
|WHERE descr LIKE '" + СокрЛП(ПолеПоиска) + "%'
|AND isfolder = 2
|AND ismark = 0";
// Выполняем запрос и загружаем результат в таблицу значений на форме
ТЗ = Запрос.ВыполнитьЗапрос(ТекстЗапроса);
ТабВиб.Загрузить(ТЗ);
КонецПроцедуры
Разберем параметры запроса подробнее:
Зачастую просто найти товар недостаточно — пользователю на ТСД нужно сразу видеть актуальный остаток. Выполнять запрос остатка для каждого найденного товара отдельно (в цикле) — это архитектурная ошибка. Правильнее объединить (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.
Чтобы сделать поиск по-настоящему «летающим», воспользуемся дополнительными приемами из практики разработки на 1С 7.7:
ПоискПоБукв() вызывалась автоматически при каждом нажатии клавиши, нужно перехватывать событие клавиатуры. В FormEx это делается через метод ПриНажатииКлавиши. Без этого пользователю придется нажимать Enter или переходить между полями, что убивает идею динамического подбора.Сервис.ВключитьТаймер() в FormEx.ТаблицаЗначений.Для того чтобы SQL-запрос работал мгновенно, убедитесь, что в конфигураторе для справочника включена «Сортировка по наименованию». Это создает индекс в файле .cdx, который компонента 1sqlite будет использовать для ускорения оператора LIKE. Если вы используете поиск по вхождению в середине строки (LIKE '%текст%'), помните, что индексы в этом случае не работают, и на справочниках более 50 000 элементов возможны задержки.
Использование связки 1sqlite + прямые запросы превращает старую добрую «семерку» в современный инструмент, способный конкурировать с восьмой платформой по скорости отклика интерфейса в задачах складского учета и оперативного подбора товаров.