При работе с запросами в 1С, особенно с виртуальными таблицами регистров бухгалтерии, программисты часто сталкиваются с задачей: необходимо вывести данные по конкретному счету, если он выбран пользователем, или по всем счетам сразу, если параметр оставлен пустым. В системе компоновки данных (СКД) это решается автоматически с помощью фигурных скобок, но в обычном программном запросе или при работе через Web-сервисы требуется особый подход. Рассмотрим подробнее, как правильно реализовать такой отбор несколькими способами.
Часто начинающие разработчики пытаются использовать конструкцию вида &Счет В (Счет) или Счет = &Счет непосредственно в параметрах виртуальной таблицы. Однако, если в параметр &Счет передать пустую ссылку или Неопределено, запрос вернет пустой результат, так как он будет пытаться найти записи, где поле Счет также пустое, чего в реальном регистре бухгалтерии практически не бывает. Проанализируем ситуацию: нам нужно, чтобы условие либо «срабатывало», либо «игнорировалось» в зависимости от состояния параметра.
Этот способ считается наиболее надежным и производительным, так как он исключает лишнюю логику из итогового SQL-запроса, который отправляется на сервер базы данных. Разберем по шагам, как это реализовать. Вместо того чтобы прописывать жесткое условие в тексте запроса, мы оставим там «маркер» или просто будем конкатенировать (склеивать) строку запроса.
Рассмотрим пример кода, где условие подставляется динамически:
Если ЗначениеЗаполнено(ВыбранныйСчет) Тогда
УсловиеСчета = "Счет В ИЕРАРХИИ(&Счет)";
Запрос.УстановитьПараметр("Счет", ВыбранныйСчет);
Иначе
// Если счет не выбран, передаем "ИСТИНА", чтобы условие не ограничивало выборку
УсловиеСчета = "ИСТИНА";
КонецЕсли;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстаткиИОбороты.Счет КАК Счет,
| ХозрасчетныйОстаткиИОбороты.СуммаОборотДт КАК СуммаДт
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&Начало, &Конец, , , " + УсловиеСчета + ", , ) КАК ХозрасчетныйОстаткиИОбороты";
В данном примере мы используем переменную УсловиеСчета. Если пользователь выбрал счет, мы применяем оператор В ИЕРАРХИИ, который позволяет захватить не только сам счет, но и все его субсчета. Если же счет не выбран, мы подставляем ИСТИНА (или просто пустую строку, если синтаксис позволяет), и виртуальная таблица возвращает данные по всем счетам. Это наиболее эффективный метод с точки зрения СУБД.
Если вы не хотите динамически менять текст запроса (например, запрос очень большой и сложный), можно использовать логическое условие «ИЛИ». Для этого в запрос передается дополнительный параметр-флаг, который сигнализирует о том, заполнен ли счет.
Проанализируем пример такого запроса:
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстаткиИОбороты.Счет КАК Счет,
| ХозрасчетныйОстаткиИОбороты.СуммаКонечныйОстаток КАК Остаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(
| &Начало,
| &Конец, , ,
| (&ВсеСчета ИЛИ Счет В ИЕРАРХИИ (&Счет)), ,
| ) КАК ХозрасчетныйОстаткиИОбороты";
Запрос.УстановитьПараметр("Счет", ВыбранныйСчет);
Запрос.УстановитьПараметр("ВсеСчета", НЕ ЗначениеЗаполнено(ВыбранныйСчет));
Как это работает? Если ВыбранныйСчет пуст, параметр &ВсеСчета принимает значение ИСТИНА. В логике запроса выражение (ИСТИНА ИЛИ Счет В ИЕРАРХИИ (&Счет)) всегда будет давать ИСТИНА для любой строки, и фильтрация по счету фактически отключится. Если же счет выбран, &ВсеСчета будет ЛОЖЬ, и сработает вторая часть условия.
Важный момент: использование оператора ИЛИ в условиях запроса может замедлить выполнение на очень больших объемах данных, так как оптимизатор СУБД не всегда может эффективно использовать индексы в таких случаях. Для большинства типовых задач этот метод вполне приемлем.
При передаче данных между базами (например, из БП 3.0 в УПП), как упоминалось в обсуждении, возникают сложности с типами данных. Если вы передаете параметр через Web-сервис, он может прийти как Строка (GUID или Код счета) или Неопределено.
Рассмотрим рекомендации для таких случаев:
ПланыСчетов.Хозрасчетный.НайтиПоКоду(КодСчета).Неопределено прямо в тексте запроса. 1С может выдать ошибку «Неверные параметры в операции сравнения». Лучше заранее подготовить параметр в коде 1С:Предприятие.Неопределено в параметрах запроса лучше использовать ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ПустаяСсылка).Посмотрим на пример обработки параметра в Web-сервисе:
Функция ПолучитьДанныеПоСчету(КодСчета) Экспорт
СсылкаНаСчет = ПланыСчетов.Хозрасчетный.НайтиПоКоду(КодСчета);
Запрос = Новый Запрос;
ТекстУсловия = "";
Если ЗначениеЗаполнено(СсылкаНаСчет) Тогда
ТекстУсловия = "Счет В ИЕРАРХИИ(&Счет)";
Запрос.УстановитьПараметр("Счет", СсылкаНаСчет);
Иначе
ТекстУсловия = "ИСТИНА";
КонецЕсли;
// Подстановка в запрос...
КонецФункции
В бухгалтерском учете структура счетов иерархична. Если мы укажем Счет = &Счет и выберем счет 41 «Товары», мы не получим данные по субсчетам 41.01, 41.02 и так далее. Выясним причину: в проводках (движениях регистра) всегда указывается конечный субсчет. Поэтому для получения корректных итогов по группе счетов использование оператора В ИЕРАРХИИ является обязательным условием. Если вы хотите разрешить выбор только конкретного списка счетов, передавайте в параметр Массив и используйте оператор В (&МассивСчетов).
Мы проанализировали основные способы работы с необязательными фильтрами. Подведем итоги:
{}.СтрЗаменить или конкатенацию строк. Это обеспечит максимальную производительность.&ВсеСчета), если вам нужно сохранить текст запроса неизменным и вы уверены в производительности системы.Следуя этим правилам, вы сможете создавать гибкие и быстрые отчеты, которые корректно обрабатывают параметры любой сложности.