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