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