В практике разработки на платформе 1С:Предприятие часто встречается ситуация: отчет, который исправно работал годами, внезапно перестает фильтровать данные по параметру, содержащему список значений. При этом одиночные значения отрабатывают корректно, а отладчик СКД может показывать, что параметр вовсе «не установлен», хотя программно вы его передали. Давайте подробно разберем причины этого поведения, связанные с особенностями механизмов компоновки данных, и найдем надежные способы решения задачи.
Одной из главных причин сбоя параметров-списков является работа внутреннего оптимизатора СКД, особенно в сложных запросах с использованием оператора ОБЪЕДИНИТЬ (UNION). Проанализируем, что происходит «под капотом» компоновщика.
Когда мы используем параметр в условии ГДЕ Поле В (&Параметр), СКД пытается оптимизировать выполнение запроса на уровне СУБД. Если ваш набор данных состоит из нескольких объединенных таблиц, компоновщик применяет механизм Push-down — он «пробрасывает» это условие внутрь каждой части объединения. Если в одной из частей объединения поле, по которому идет фильтрация, отсутствует или СКД не может однозначно сопоставить его с параметром, генерируемый SQL-запрос становится некорректным. В итоге мы видим пустой результат или ошибку о том, что параметр не определен, так как контекст его использования был нарушен при генерации макета компоновки.
Рассмотрим важный технический нюанс. Объект СписокЗначений является типом данных платформы 1С, предназначенным в первую очередь для интерфейсных решений. Внутри механизмов СКД (особенно в новых релизах платформы, начиная с 8.3.15) обработка этого объекта может приводить к сбоям при передаче в SQL-запрос.
Проанализируем ситуацию: для оператора В (&Параметр) в тексте запроса СКД гораздо стабильнее воспринимает простой Массив. Если вы устанавливаете параметр программно, попробуйте выгрузить значения из списка в массив перед передачей. Посмотрим на пример кода:
// Вместо прямой передачи списка значений
// НастройкиКомпоновки.ПараметрыДанных.УстановитьЗначениеПараметра("Договоры", СписокДоговоров);
// Используем выгрузку в массив
МассивДоговоров = СписокДоговоров.ВыгрузитьЗначения();
НастройкиКомпоновки.ПараметрыДанных.УстановитьЗначениеПараметра("Договоры", МассивДоговоров);
Этот простой шаг часто решает проблему «неустановленного» параметра, так как массив — это примитивная коллекция, которую компоновщик легко преобразует в список констант для SQL-оператора IN.
Если проблема вызвана объединением таблиц (UNION), как это было описано в сообщениях форума, нам нужно помочь компоновщику правильно обработать условия. Выясним причину: когда условие написано жестко в тексте запроса, СКД обязана применить его ко всем веткам объединения.
Рассмотрим применение расширения языка запросов СКД — фигурных скобок {}. Это позволяет сделать условие «необязательным» для компоновщика, и он будет применять его только там, где это логически возможно. Перепишем наше условие в запросе:
ВЫБРАТЬ
Продажи.Договор,
Продажи.Сумма
ИЗ
РегистрНакопления.Продажи КАК Продажи
{ГДЕ
(Продажи.Договор В (&КосвенныеДоговорыЗайма))}
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Оплаты.Договор,
Оплаты.Сумма
ИЗ
РегистрНакопления.Оплаты КАК Оплаты
{ГДЕ
(Оплаты.Договор В (&КосвенныеДоговорыЗайма))}
Использование конструкции {ГДЕ ...} гарантирует, что если в какой-то части сложного запроса параметр не может быть применен корректно, СКД просто исключит его из этой части, не ломая структуру всего отчета.
Если программная установка параметра в ПараметрыДанных всё равно дает сбои, проанализируем альтернативный путь — использование механизма Отборов СКД. Отборы работают на более высоком уровне абстракции и считаются более стабильными при работе с объединениями и вложенными запросами.
Для этого в схеме СКД на вкладке «Настройки» мы можем добавить отбор по нужному полю, а программно заполнять его следующим образом:
// Найдем нужный элемент отбора по имени поля
ПолеОтбора = Новый ПолеКомпоновкиДанных("Договор");
ЭлементОтбора = Неопределено;
Для Каждого Элемент Из НастройкиКомпоновки.Отбор.Элементы Цикл
Если Элемент.ЛевоеЗначение = ПолеОтбора Тогда
ЭлементОтбора = Элемент;
Прервать;
КонецЕсли;
КонецЦикла;
Если ЭлементОтбора = Неопределено Тогда
ЭлементОтбора = НастройкиКомпоновки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = ПолеОтбора;
КонецЕсли;
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = МассивДоговоров;
ЭлементОтбора.Использование = Истина;
Этот метод позволяет избежать прямого редактирования текста запроса параметрами и отдает управление фильтрацией самому движку компоновки, который эффективнее справляется с распределением условий по таблицам.
Часто программисты забывают явно указать тип значения для параметра на вкладке «Параметры» в конструкторе СКД. Если тип оставлен пустым, то при передаче СпискаЗначений компоновщик может неправильно типизировать значения в SQL-запросе, что приведет к ошибке сравнения (например, попытка сравнить ссылку с числом или строкой).
Рекомендуем:
&КосвенныеДоговорыЗайма).СправочникСсылка.ДоговорыКонтрагентов).Подводя итог, если у вас перестал работать параметр-список в СКД, придерживайтесь следующего алгоритма действий:
UNION. Если используется — оберните условия в фигурные скобки {}.СписокЗначений на Массив с помощью метода ВыгрузитьЗначения().НастройкиКомпоновки.Отбор).Помните, что поведение СКД может меняться от релиза к релизу платформы. Использование стандартных массивов и механизмов отбора — самый надежный способ обеспечить долгосрочную работоспособность ваших отчетов.