Работа со строками в языке запросов 1С:Предприятия 7.7 существенно отличается от более современных версий платформы. Одной из наиболее частых проблем, с которыми сталкиваются разработчики, является некорректная работа функции Найти() внутри секции Условие. Рассмотрим ситуацию, когда при поиске фрагмента артикула или наименования запрос выдает пустой результат или находит данные выборочно, хотя искомая подстрока визуально присутствует в базе данных.
Разберем типичный пример. У нас есть справочник КодТовара, где хранятся артикулы поставщиков. Мы пытаемся найти все записи, в наименовании которых встречается определенная последовательность символов, например, "T131401". Однако запрос возвращает результат только при полном совпадении или не находит ничего, даже если в справочнике есть строка "T1314011".
Первая и самая распространенная причина — это наличие лишних пробелов в переменной, которая передается в запрос. В 1С 7.7 элементы экранных форм (текстовые поля) часто имеют фиксированную длину. Если длина поля на форме составляет 20 символов, а пользователь ввел только 7, платформа автоматически дополняет строку пробелами до конца длины поля. В итоге функция Найти() ищет не "T131401", а "T131401 ". Очевидно, что такое вхождение в реальных данных отсутствует.
Проанализируем фрагмент кода, который приводит к ошибке:
ВыбФрагмент = "T131401"; // На самом деле здесь могут быть невидимые пробелы из формы
ТекстЗапроса = "
|КакУПоставщика = Справочник.КодТовара.Наименование;
|Условие(Найти(КакУПоставщика, ВыбФрагмент) > 0);
|";
Для исправления ситуации необходимо гарантировать, что искомая подстрока не содержит лишних пробелов в начале и в конце. Для этого перед формированием текста запроса следует использовать функцию СокрЛП(). Посмотрим на правильную реализацию:
// Создаем вспомогательную переменную для поиска
ФрагментПоиска = СокрЛП(ВыбФрагмент);
Если ПустаяСтрока(ФрагментПоиска) = 1 Тогда
Сообщить("Введите текст для поиска!");
Возврат;
КонецЕсли;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "//{{ЗАПРОС(Сформировать)
|КакУПоставщика = Справочник.КодТовара.Наименование;
|Группировка КакУПоставщика;
|Условие(Найти(КакУПоставщика, ФрагментПоиска) <> 0);
|"//}}ЗАПРОС
;
Обратите внимание на использование оператора <> 0 вместо > 0. Хотя логически они похожи, в некоторых версиях движка баз данных (особенно в SQL-варианте 7.7) явная проверка на неравенство нулю считается более надежной при работе со встроенными функциями запроса.
Иногда полезно принудительно привести типы данных внутри самого запроса, используя функцию Строка(). Это помогает избежать проблем, если реквизит справочника имеет неопределенный тип или является ссылкой. Рассмотрим, как выглядит такой "усиленный" запрос:
|Условие(Найти(Строка(КакУПоставщика), Строка(ФрагментПоиска)) > 0);
Однако стоит помнить, что избыточное использование функции Строка() внутри цикла обхода записей запроса может замедлить выполнение, так как платформа будет выполнять преобразование для каждой сканируемой строки таблицы.
Важно понимать, как 1С 7.7 исполняет такие запросы. Когда мы используем Найти() в секции Условие, мы лишаем систему возможности использовать индексы базы данных. Проанализируем последствия:
Найти() в 7.7 может быть чувствительна к регистру символов. Если вы ищете "артикул", а в базе записано "АРТИКУЛ", поиск может завершиться неудачей. Для решения этой проблемы часто используют перевод обеих частей сравнения в верхний регистр (функция Врег()), но в стандартном языке запросов 7.7 функция Врег() внутри Условие() не поддерживается.Если справочник очень большой и поиск по фрагменту требуется выполнять часто, программисты часто прибегают к использованию внешних компонент, таких как 1C++. Это позволяет писать прямые SQL-запросы, используя оператор LIKE:
// Пример логики прямого запроса через 1С++
ТекстSQL = "
|SELECT id as [Элемент $Справочник.КодТовара]
|FROM $Справочник.КодТовара
|WHERE $Справочник.КодТовара.Наименование LIKE '%" + ФрагментПоиска + "%'
|";
Такой подход работает в десятки раз быстрее стандартного объекта Запрос, так как SQL-сервер гораздо эффективнее справляется с поиском подстрок.
Если задача стоит в поиске артикулов, которые могут иметь разные форматы написания (с тире, точками, пробелами), проанализируем возможность создания "индексного" реквизита. Вы можете добавить в справочник скрытый реквизит НаименованиеДляПоиска, в который при записи элемента программно сохранять очищенное от лишних символов значение (в верхнем регистре и без разделителей). Поиск по такому полю будет гораздо точнее и быстрее.
Подведем итог: для корректной работы поиска в 1С 7.7 всегда обрезайте пробелы функцией СокрЛП() у искомого значения и следите за тем, чтобы искомый фрагмент не был пустой строкой, иначе запрос может вернуть все записи справочника или выдать ошибку выполнения.