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