Почему в СКД не работает оператор ПОДОБНО с диапазонами и как корректно выводить внешние функции в таблицу значений?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с ситуациями, когда стандартное поведение платформы кажется ошибочным. Рассмотрим две серьезные проблемы: игнорирование внешних функций при программном выводе в ТаблицуЗначений и «странное» поведение оператора ПОДОБНО при попытке использовать диапазоны вида [0-9]. Проанализируем причины такого поведения и разберем готовые программные решения для обхода ограничений.

Проблема первая: Внешние функции и вывод в таблицу значений

Рассмотрим ситуацию: в схеме компоновки данных создано поле, которое обращается к функции общего модуля (например, для получения номера документа без префикса). При формировании отчета в Поле табличного документа всё работает корректно — функция вызывается, данные заполняются. Однако при попытке программно выгрузить этот же результат в ТаблицуЗначений, поле оказывается пустым или функция вовсе не срабатывает. Почему так происходит?

Разберем причину. Когда мы используем ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент, платформа работает в режиме формирования визуального представления. Здесь процессор компоновки более гибко управляет вычислениями. При использовании же ПроцессорВыводаРезультатаКомпоновкиДанныхВТаблицуЗначений платформа применяет механизмы оптимизации. Если система считает, что данные можно получить напрямую из БД, она пытается минимизировать постобработку.

Чтобы гарантированно получить результат внешней функции в таблице значений, рекомендуется придерживаться следующих правил:

  1. Настройка модуля: Общий модуль, в котором находится функция, должен иметь установленные флаги Сервер, Внешнее соединение и Вызов сервера.
  2. Использование вычисляемых полей: Вместо того чтобы вставлять вызов функции непосредственно в текст запроса СКД, создадим Вычисляемое поле на соответствующей вкладке конструктора. В выражении этого поля пропишем путь к функции: ОбщийМодульИмя.ИмяФункции(ПолеЗапроса). Это заставит процессор компоновки вычислить значение на стороне сервера приложений после получения сырых данных из СУБД.
  3. Детальные записи: При выводе в таблицу значений убедимся, что в настройках компоновки выбрана группировка Детальные записи, иначе функции для групповых полей могут не рассчитаться без агрегатных функций.

Проблема вторая: Ограничения оператора ПОДОБНО и шаблоны [0-9]

Ситуация вторая: нам нужно найти в справочнике или документах строки, соответствующие определенному шаблону, например, содержащие цифры. Мы пишем условие Комментарий ПОДОБНО "%CX[0-9]%". К нашему удивлению, СКД не выдает никаких результатов, хотя прямой запрос к базе данных с этим же текстом работает отлично. Выясним причину.

Проанализируем работу СКД «под капотом». Система компоновки данных спроектирована как кросс-платформенное решение, которое должно одинаково работать на MS SQL Server, PostgreSQL, IBM DB2 и Oracle. Однако синтаксис LIKE с квадратными скобками [] является специфичным для T-SQL (Microsoft) и поддерживается не всеми СУБД. Чтобы обеспечить стабильность, СКД при генерации макета компоновки автоматически экранирует спецсимволы.

Когда мы задаем отбор, СКД находит символы [, %, _ и вставляет перед ними служебный символ (чаще всего это / или #), добавляя в запрос конструкцию СПЕЦСИМВОЛ '/'. В итоге СУБД ищет в строке буквальное вхождение символа «[», а не начало диапазона цифр.

Программный способ обхода экранирования

Чтобы заставить СКД выполнять «честный» поиск по шаблону, нам придется вмешаться в процесс компоновки макета. Мы будем использовать программное формирование отчета и корректировать уже сгенерированный макет перед тем, как передать его процессору компоновки.

Рассмотрим пошагово алгоритм решения задачи. Сначала мы компонуем макет стандартным способом, а затем проходим по всем параметрам макета и очищаем их от добавленных системой экранирующих символов. Посмотрим на пример кода:


// 1. Получаем настройки и компонуем макет
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки);

// 2. Исправляем экранирование в значениях параметров макета
Для каждого ПараметрМакета Из МакетКомпоновки.ЗначенияПараметров Цикл
    Если ТипЗнч(ПараметрМакета.Значение) = Тип("Строка") Тогда
        // Убираем символ "/", который СКД добавила перед скобкой
        ПараметрМакета.Value = СтрЗаменить(ПараметрМакета.Значение, "/[", "[");
        ПараметрМакета.Value = СтрЗаменить(ПараметрМакета.Значение, "/%", "%");
        ПараметрМакета.Value = СтрЗаменить(ПараметрМакета.Значение, "/_", "_");
    КонецЕсли;
КонецЦикла;

Однако этого может быть недостаточно. Если отбор установлен не в общих настройках, а в конкретной группировке, значение отбора попадает не в параметры, а непосредственно в «тело» макета (в свойство ОтборЗаписей). Разберем, как обработать и этот случай с помощью рекурсивной процедуры.

Рекурсивная очистка отборов в теле макета

Проанализируем ситуацию, когда спецсимвол может меняться динамически. Система может использовать разные знаки экранирования. Нам нужно найти конструкцию СПЕЦСИМВОЛ и корректно обработать текст. Посмотрим на реализацию процедуры:


Процедура ИсправитьОтборТелаМакета(ЭлементМакет) Экспорт
    // Проходим по всем элементам тела макета (группировкам)
    Для Каждого ЭлементТела Из ЭлементМакет.Тело Цикл
        Если ТипЗнч(ЭлементТела) = Тип("ГруппировкаМакетаКомпоновкиДанных") Тогда
            
            // Проверяем наличие установленного отбора и ключевого слова СПЕЦСИМВОЛ
            Если ЗначениеЗаполнено(ЭлементТела.ОтборЗаписей) 
                И СтрНайти(ВРег(ЭлементТела.ОтборЗаписей), "СПЕЦСИМВОЛ") <> 0 Тогда
                
                МассивПолногоОтбора = Новый Массив;
                ПозицияНачала = 1;
                // Ищем вхождение ключевого слова
                ПозицияСпецСимвола = СтрНайти(ВРег(ЭлементТела.ОтборЗаписей), "СПЕЦСИМВОЛ", , ПозицияНачала, 1);
                
                Пока ПозицияСпецСимвола > 0 Цикл
                    // Определяем, какой именно символ используется для экранирования (обычно через 12 символов после начала слова)
                    ТекСпецСимвол = Сред(ЭлементТела.ОтборЗаписей, ПозицияСпецСимвола + 12, 1);
                    
                    // Очищаем блок текста от этого символа
                    БлокЗамены = СтрЗаменить(Сред(ЭлементТела.ОтборЗаписей, ПозицияНачала, ПозицияСпецСимвола - ПозицияНачала), ТекСпецСимвол, "");
                    МассивПолногоОтбора.Добавить(БлокЗамены);
                    
                    // Оставляем само описание спецсимвола, если СУБД его требует, или можно удалить конструкцию целиком
                    // В данном примере мы корректируем длину шага
                    ПозицияНачала = ПозицияСпецСимвола + 14; 
                    
                    Если ПозицияНачала < СтрДлина(ЭлементТела.ОтборЗаписей) Тогда
                        ПозицияСпецСимвола = СтрНайти(ВРег(ЭлементТела.ОтборЗаписей), "СПЕЦСИМВОЛ", , ПозицияНачала, 1);
                        Если ПозицияСпецСимвола = 0 Тогда
                            МассивПолногоОтбора.Добавить(Сред(ЭлементТела.ОтборЗаписей, ПозицияНачала));
                        КонецЕсли;
                    Иначе
                        ПозицияСпецСимвола = 0;
                    КонецЕсли;
                КонецЦикла;
                
                ЭлементТела.ОтборЗаписей = СтрСоединить(МассивПолногоОтбора, "");
            КонецЕсли;
            
            // Рекурсивно заходим в дочерние группировки
            ИсправитьОтборТелаМакета(ЭлементТела);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Подведем итоги

Мы выяснили, что СКД — это мощный, но иногда избыточно «осторожный» инструмент. Автоматическое экранирование создано для защиты от ошибок на разных СУБД, но оно блокирует использование мощных возможностей оператора ПОДОБНО.

Для успешного решения подобных задач запомним основные правила:

Использование предложенных методов позволит вам создавать гибкие и сложные отчеты, не ограничиваясь стандартными рамками визуального конструктора СКД.

← На главную