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