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

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

При разработке отчетов и обработок в платформе 1С:Предприятие 7.7 часто возникает задача отобрать документы или конкретные строки табличной части по текстовому реквизиту — например, найти документ сервиса по серийному номеру или названию номенклатуры. Однако встроенный язык запросов 7.7 имеет ряд синтаксических нюансов, из-за которых запрос может отрабатывать без ошибок, но возвращать пустой результат.

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

Причины, по которым запрос 1С 7.7 возвращает пустую выборку

Проанализируем распространенные ошибки при построении запросов к документам в платформе 1С 7.7:

  1. Отсутствие директивы периода: Если в тексте запроса не задана конструкция Период с ... по ...;, платформа не выбирает данные за всю историю базы данных автоматически. Выборка может позиционироваться на текущую дату или остаться пустой.
  2. Статус проведения документов: По умолчанию встроенный запрос 7.7 выбирает только проведенные документы. Если искомый документ не проведен или помечен на удаление, в запрос необходимо обязательно добавить директиву ОбрабатыватьДокументы все;.
  3. Ошибки в синтаксисе обхода группировок: Метод Запрос.Группировка() требует правильной структуры циклов. При наличии нескольких уровней группировок их необходимо обходить последовательно во вложенных циклах с указанием имени или номера группировки.
  4. Пробелы в строковых реквизитах фиксированной длины: Реквизиты типа Строка фиксированной длины в базе данных дополняются пробелами справа. Если сравнивать строку без обрезки пробелов, условие точного равенства может не сработать.

Вариант 1. Поиск по подстроке с использованием оператора «В»

Рассмотрим синтаксис оператора вхождения в. В языке запросов 1С 7.7 данный оператор работает не только со списками значений, но и с обычными строками, проверяя факт вхождения подстроки в строку.

Важное правило синтаксиса: искомая подстрока должна указываться слева от оператора в, а строковое поле базы данных — справа. Чтобы исключить влияние хвостовых пробелов, к реквизиту применяется функция СокрЛП().

Посмотрим на готовый пример процедуры поиска строк табличной части документа по вхождению серийного номера:


Процедура НайтиПоПодстроке()
    Перем Запрос, ТекстЗапроса;
    
    СерийныйНомерС = "123";
    
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = 
    "//{{ЗАПРОС(ПоискПоПодстроке)
    |Период с ВыбНачПериода по ВыбКонПериода;
    |ОбрабатыватьДокументы все;
    |ТекущийДокумент = Документ.ДокументСервиса.ТекущийДокумент;
    |Картридж = Документ.ДокументСервиса.Картридж;
    |СерийныйНомер = Документ.ДокументСервиса.СерийныйНомер;
    |Группировка ТекущийДокумент;
    |Группировка Картридж без Групп;
    |Условие(СерийныйНомерС в СокрЛП(СерийныйНомер));
    |"//}}ЗАПРОС
    ;
    
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Предупреждение("Ошибка выполнения запроса!");
        Возврат;
    КонецЕсли;
    
    Пока Запрос.Группировка("ТекущийДокумент") = 1 Цикл
        Пока Запрос.Группировка("Картридж") = 1 Цикл
            Сообщить("Документ: " + Запрос.ТекущийДокумент + " | Картридж: " + Запрос.Картридж);
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры

Вариант 2. Точное совпадение строки без учета регистра

Если требуется найти не произвольное вхождение, а строгое совпадение значения строкового реквизита, оператор в заменяется на знак равенства =. Чтобы исключить несовпадение из-за разного регистра символов или лишних пробелов, обе части сравнения оборачиваются в функции ВРег() и СокрЛП().

Рассмотрим пример формирования условия для точного поиска:


ТекстЗапроса = 
"//{{ЗАПРОС(ТочныйПоиск)
|Период с ВыбНачПериода по ВыбКонПериода;
|ОбрабатыватьДокументы все;
|ТекущийДокумент = Документ.ДокументСервиса.ТекущийДокумент;
|Картридж = Документ.ДокументСервиса.Картридж;
|СерийныйНомер = Документ.ДокументСервиса.СерийныйНомер;
|Группировка ТекущийДокумент;
|Группировка Картридж без Групп;
|Условие(ВРег(СокрЛП(СерийныйНомер)) = ВРег(СокрЛП(СерийныйНомерС)));
|"//}}ЗАПРОС
;

Вариант 3. Использование функции «Найти»

Альтернативным способом поиска подстроки является применение встроенной строковой функции Найти() внутри секции Условие(). Следует помнить, что функция Найти() чувствительна к регистру символов, поэтому при необходимости регистронезависимого поиска строки предварительно приводятся к верхнему регистру:


ТекстЗапроса = 
"//{{ЗАПРОС(ПоискНайти)
|Период с ВыбНачПериода по ВыбКонПериода;
|ОбрабатыватьДокументы все;
|ТекущийДокумент = Документ.ДокументСервиса.ТекущийДокумент;
|Картридж = Документ.ДокументСервиса.Картридж;
|СерийныйНомер = Документ.ДокументСервиса.СерийныйНомер;
|Группировка ТекущийДокумент;
|Группировка Картридж без Групп;
|Условие(Найти(ВРег(СерийныйНомер), ВРег(СерийныйНомерС)) > 0);
|"//}}ЗАПРОС
;

Рекомендации по оптимизации запросов к табличным частям

  1. Всегда ограничивайте период: Поиск по строковым полям табличных частей не использует индексы базы данных и выполняется полным перебором записей. Четкое указание дат начала и конца периода существенно сокращает время выполнения.
  2. Использование директивы «Без итогов»: Если в запросе не вычисляются агрегатные функции (например, сумма или количество через Функция), использование директивы Без итогов; уменьшает объем потребляемой памяти и ускоряет выборку.
  3. Поиск по списку значений: Если необходимо проверить принадлежность серийного номера списку возможных значений, оператор в применяется со списком: Условие(СерийныйНомер в СписокСерийников);, где СписокСерийников — объект типа СписокЗначений.
← На главную