Как в запросе 1С 7.7 сравнить строку, содержащую кавычки, и оптимизировать поиск по списку наименований

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

Работа с так называемыми "черными запросами" в 1С:Предприятии 7.7 часто преподносит сюрпризы, особенно когда дело касается обработки строковых данных со спецсимволами. Одной из классических проблем является наличие символа двойной кавычки " внутри наименований элементов справочника. Попытка стандартного экранирования кавычек в тексте запроса часто приводит к синтаксическим ошибкам типа "Ожидается ')' перед...". В этой статье мы разберем, почему так происходит, и проанализируем наиболее эффективные способы решения этой задачи.

Почему возникает ошибка при обработке кавычек в запросе

Проанализируем ситуацию: когда мы динамически формируем текст запроса и пытаемся вставить условие вида Условие(Наименование = "Светильник ""Кольца"""), внутренний парсер 1С 7.7 может некорректно интерпретировать последовательность кавычек. В отличие от встроенного языка программных модулей, парсер запросов имеет свои ограничения. При достижении определенных комбинаций символов он "теряет" закрывающую скобку условия, считая, что строка завершилась раньше времени.

Ситуация осложняется, если список искомых наименований исчисляется сотнями. Конкатенация условий через ИЛИ превращает текст запроса в огромную нечитаемую строку, которая не только работает медленно, но и может упереться в лимит длины строки текста запроса (около 32 768 символов).

Решение №1: Использование списка значений и метода НайтиЗначение

Рассмотрим наиболее изящный и производительный способ. Вместо того чтобы вписывать каждое наименование в текст запроса, мы передадим в запрос объект СписокЗначений и будем проверять вхождение текущего наименования в этот список непосредственно в условии.

Разберем этот метод по шагам:

  1. Заполним СписокЗначений всеми необходимыми наименованиями (например, прочитанными из внешнего файла DBF).
  2. В тексте запроса определим переменную для наименования.
  3. В секции Условие вызовем метод НайтиЗначение() для нашего списка.

Посмотрим на пример кода:


// Предположим, СписокНаименований уже заполнен строками из файла
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Без итогов;
|Наим = Справочник.Материалы.Наименование;
|Цена = Справочник.Материалы.Цена;
|Материал = Справочник.Материалы.ТекущийЭлемент;
|Группировка Материал без групп;
|Условие(СписокНаименований.НайтиЗначение(СокрП(Наим)) <> 0);
|";

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
    Возврат;
КонецЕсли;

Важный момент: использование СокрП() внутри условия позволяет избежать проблем с лишними пробелами в конце строк, которые часто встречаются в базе данных. Этот метод полностью снимает проблему кавычек, так как сравнение строк происходит внутри метода НайтиЗначение, где объектная модель 1С корректно обрабатывает любые символы.

Решение №2: Использование внешней функции в условии

Если логика сравнения более сложная (например, нужно проверять одновременно и цену, и наименование, или проводить нечеткий поиск), мы можем вынести проверку во внешнюю функцию модуля. Выясним, как это работает: запрос для каждой итерации перебора данных будет обращаться к функции в контексте модуля обработки.

Пример реализации функции и запроса:


Функция ПроверитьСтроку(ТекНаим, ТекЦена)
    // Здесь можно реализовать любую сложную логику
    // Переменная СЗ_Ключи — это предварительно подготовленный СписокЗначений
    КлючПоиска = СокрП(ТекНаим) + "|" + Строка(ТекЦена);
    Если СЗ_Ключи.НайтиЗначение(КлючПоиска) > 0 Тогда
        Возврат 1; // Условие выполняется
    КонецЕсли;
    Возврат 0;
КонецФункции

// В тексте запроса
ТекстЗапроса = "
// ... (описание переменных запроса)
|Условие(ПроверитьСтроку(Наим, Цена) = 1);
|";

Рассмотрим подробнее минусы этого подхода: вызов функции из запроса существенно замедляет выполнение, так как происходит постоянное переключение контекста между движком запроса и интерпретатором языка. Однако для небольших и средних справочников это решение является максимально гибким.

Решение №3: Борьба с регистрозависимостью и нормализация данных

Проанализируем ситуацию, когда запрос "не находит" элементы, хотя визуально они идентичны. В 1С 7.7 поиск по строке может быть чувствителен к регистру (в зависимости от настроек базы и используемого драйвера БД). Чтобы поиск работал стабильно, рекомендуется проводить нормализацию данных перед поиском.

Разберем, как правильно подготовить данные:

  1. При заполнении списка поиска переводите все строки в верхний регистр с помощью ВРег().
  2. В условии запроса также используйте ВРег() для текущего значения из справочника.
  3. Очищайте строки от непечатных символов и лишних пробелов.

Пример функции нормализации:


Функция Нормализовать(Стр)
    // Удаляем лишние пробелы и приводим к одному регистру
    Возврат ВРег(СокрЛП(Стр));
КонецФункции

При добавлении в СписокНаименований используйте СписокНаименований.ДобавитьЗначение(Нормализовать(ЗначениеИзФайла)). Соответственно, условие в запросе примет вид: Условие(СписокНаименований.НайтиЗначение(ВРег(СокрП(Наим))) <> 0);.

Особенности работы оператора "В" в 1С 7.7

Многие программисты пытаются использовать конструкцию Условие(Наим В СписокНаименований). Посмотрим на нюанс, о котором часто забывают: в "семерке" оператор В для строковых данных при работе со списками значений иногда ведет себя как поиск по началу строки (аналог LIKE 'строка%'). Это может привести к тому, что при поиске наименования "Лампа" в выборку попадут и "Лампа 60W", и "Лампа Navigator".

Именно поэтому использование СписокЗначений.НайтиЗначение() внутри условия является более безопасным — оно гарантирует точное совпадение (если не используются дополнительные параметры поиска в методе).

Когда запроса недостаточно: использование ВыбратьЭлементыПоРеквизиту

Если ваша задача — поиск по конкретному реквизиту (например, артикулу или цене), и для этого реквизита в конфигураторе установлен признак "Сортировка" или "Отбор по реквизиту", то использование метода ВыбратьЭлементыПоРеквизиту будет работать значительно быстрее черного запроса. Однако для реквизита "Наименование" этот метод недоступен напрямую, так как наименование — это стандартный атрибут с особым индексированием.

В случае с наименованием можно использовать НайтиПоНаименованию(Искомое, 0, 1), но помните, что этот метод позиционируется только на первом найденном элементе. Если в справочнике есть дубли, вам придется использовать цикл с ПолучитьЭлемент() и ручной проверкой соответствия, что при больших объемах данных может быть неэффективно.

Итоги

Для решения проблемы кавычек в запросах 1С 7.7 наилучшим решением является отказ от динамического формирования текста условия с перечислением строк. Вместо этого:

Соблюдение этих правил позволит вам создавать надежные механизмы импорта и синхронизации данных даже в старых системах на базе 1С 7.7, не опасаясь синтаксических ошибок из-за особенностей парсинга кавычек.

← На главную