При оптимизации скорости поиска в объемных справочниках платформы 1С:Предприятие 7.7 часто прибегают к прямым запросам с помощью внешней компоненты 1sqlite. Типовой сценарий — контекстный поиск подстроки по нескольким словам в наименовании элемента. Однако при попытке переключить отбор со стандартного наименования на добавленный реквизит (например, Артикул, НомерТелефона или Комментарий) разработчики нередко сталкиваются с ошибками выполнения запроса. Выясним причину такого поведения и разберем по шагам, как правильно адресовать реквизиты в виртуальных таблицах 1sqlite.
Рассмотрим исходную ситуацию: в справочнике контактных лиц или номенклатуры реализован поиск по наименованию (системному полю descr) с разбиением введенной поисковой фразы на отдельные слова:
РазбиваемаяСтрока = СтрЗаменить(РазбиваемаяСтрока, "'", "''");
РазбиваемаяСтрока = СтрЗаменить(СокрЛП(стрПоиска), " ", РазделительСтрок);
текст = "SELECT
|code Код,
|id [КонтактноеЛицо :Справочник.КонтактныеЛица]
|FROM КонтЛица
|WHERE ismark <> '*'";
Для Индекс = 1 По СтрКоличествоСтрок(РазбиваемаяСтрока) Цикл
Слово = СтрПолучитьСтроку(РазбиваемаяСтрока, Индекс);
Если ПустоеЗначение(Слово) = 0 Тогда
текст = текст + "
|AND descr LIKE '%" + Слово + "%'";
КонецЕсли;
КонецЦикла;
При необходимости искать данные по новому добавленному реквизиту возникает соблазн заглянуть в структуру файлов базы данных через просмотрщик DBF или файл описания 1cv7.dd. Обнаружив физическое имя колонки (например, SP12547), программист подставляет его вместо descr, но запрос завершается ошибкой.
Проанализируем архитектуру работы компоненты. Модуль dbeng, отвечающий за связь SQLite с таблицами 1С 7.7, строит виртуальные таблицы на основе метаданных конфигурации, а не прямой трансляцией низкоуровневых имен DBF. Это означает следующее:
id (ссылка на объект), code (код элемента), descr (наименование), ismark (пометка на удаление, содержащая символ звездочки *), isfolder (признак папки), parentid (родительская группа) и parentext (владелец).SP12547 компонента переопределяет автоматически и в теле запроса их не распознает.Для фильтрации по пользовательскому полю достаточно указать его точное имя так, как оно задано в конфигураторе 1С. Посмотрим на пример, когда требуется искать совпадение либо в наименовании, либо в реквизите Артикул:
Для Индекс = 1 По СтрКоличествоСтрок(РазбиваемаяСтрока) Цикл
Слово = СтрПолучитьСтроку(РазбиваемаяСтрока, Индекс);
Если ПустоеЗначение(Слово) = 0 Тогда
текст = текст + "
|AND (descr LIKE '%" + Слово + "%' OR Артикул LIKE '%" + Слово + "%')";
КонецЕсли;
КонецЦикла;
Если поиск требуется вести исключительно по добавленному реквизиту, просто заменяем descr на его имя из метаданных:
текст = текст + "
|AND НомерТелефона LIKE '%" + Слово + "%'";
Разберем специфические особенности, которые необходимо учитывать при выборках через 1sqlite:
_1SCONST. В виртуальной таблице справочника колонка периодического реквизита отсутствует. Обычный отбор Реквизит LIKE ... к ним применить нельзя — потребуется связывание (LEFT JOIN) с таблицей _1SCONST и получение среза последних значений.LIKE '%...%' будет выполняться по внутреннему коду ссылки, а не по её представлению. Чтобы искать по наименованию связанного объекта, необходимо присоединять соответствующую таблицу справочника по равенству Реквизит = Справочник2.id.LIKE в базовом SQLite корректно обрабатывает регистр только для латиницы. В компоненте 1sqlite встроен модификатор сопоставления COLLATE _1C, обеспечивающий корректное сравнение кириллических строк и отсечение завершающих пробелов для строковых реквизитов фиксированной длины.'%текст%' неизбежно приводит к полному сканированию таблицы (Full Scan), так как индексные файлы .cdx не могут быть использованы при наличии знака процента в начале строки поиска. На базах с сотнями тысяч элементов такой запрос может вызывать задержки. Если допустим поиск только по началу строки ('текст%'), компонента сможет задействовать существующие индексы отбора и сортировки.