При работе с программно созданными таблицами значений (ТЗ) и передачей их в запрос в качестве параметров программисты часто сталкиваются с проблемой фильтрации данных. Одной из самых распространенных задач является поиск по части строки с использованием оператора ПОДОБНО. Однако при попытке применить этот оператор к колонке, содержащей ссылки (например, СправочникСсылка), платформа выдает ошибку: "Неверные параметры ПОДОБНО".
В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно подготовить таблицу значений для запроса и какие способы существуют для реализации поиска по строковой маске внутри временных таблиц.
Первое, что нам необходимо уяснить: оператор ПОДОБНО (LIKE) в языке запросов 1С работает исключительно со строковыми типами данных. Когда мы передаем в запрос таблицу, где в колонке Объект хранятся ссылки на элементы справочника, мы не можем напрямую написать ГДЕ Таблица.Объект ПОДОБНО &Поиск. Ссылка — это уникальный идентификатор (GUID), а не текст, который видит пользователь.
Для решения задачи нам нужно обратиться к текстовому реквизиту объекта — обычно это Наименование. Рассмотрим, как это сделать правильно, сохранив при этом возможность использования Конструктора запроса.
Если мы хотим быстро внести правки в существующий запрос, мы можем воспользоваться явным приведением типа. Это позволит Конструктору запроса понять, с каким объектом метаданных мы работаем, и даст возможность "развернуть" поля через точку.
Проанализируем пример кода запроса, где мы типизируем входящую колонку:
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Т2.Объект КАК Справочник.пто_ОбъектыОС) КАК Объект
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
| &Т2 КАК Т2
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Данные.Объект КАК Объект
|ИЗ
| ВТ_Данные КАК ВТ_Данные
|ГДЕ
| ВТ_Данные.Объект.Наименование ПОДОБНО &Поиск";
В данном случае функция ВЫРАЗИТЬ сообщает системе, что в колонке Объект гарантированно находится ссылка конкретного типа. После этого обращение Объект.Наименование становится легитимным. Однако помните: обращение через точку в условии ГДЕ порождает неявное левое соединение в SQL-запросе, что может сказаться на производительности при больших объемах данных.
Более правильным и производительным способом считается явное соединение временной таблицы с реальной таблицей справочника из базы данных. Это позволяет избежать проблем с типизацией "на лету" и дает полный контроль над выбираемыми полями.
Рассмотрим пошагово этот алгоритм:
ГДЕ накладываем условие на наименование из основной таблицы.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т1.Объект КАК СсылкаНаОбъект
|ПОМЕСТИТЬ ВТ_Исходник
|ИЗ
| &Таблица1 КАК Т1
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Т1.СсылкаНаОбъект КАК Объект,
| СпрОбъекты.Наименование КАК Наименование
|ИЗ
| ВТ_Исходник КАК Т1
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.пто_ОбъектыОС КАК СпрОбъекты
| ПО Т1.СсылкаНаОбъект = СпрОбъекты.Ссылка
|ГДЕ
| СпрОбъекты.Наименование ПОДОБНО &Поиск";
Запрос.УстановитьПараметр("Таблица1", Т1);
Запрос.УстановитьПараметр("Поиск", "%Система учета%");
Результат = Запрос.Выполнить().Выгрузить();
Важный момент: Если в вашей ТЗ могут быть пустые ссылки или ссылки разных типов, используйте ЛЕВОЕ СОЕДИНЕНИЕ и функцию ЕСТЬNULL для обработки пустых значений наименования.
Иногда проще подготовить данные до того, как они попадут в запрос. Мы можем добавить в таблицу значений отдельную строковую колонку и заполнить её наименованиями объектов. Тогда в запросе нам не придется делать никаких соединений или обращений через точку.
// Подготовим описание типов для строковой колонки
КвалификаторСтроки = Новый КвалификаторыСтроки(150);
ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка", , КвалификаторСтроки);
// Добавим колонку для поиска
Т2.Колонки.Добавить("НаименованиеДляПоиска", ОписаниеТипаСтрока);
Для Каждого СтрокаТЗ Из Т2 Цикл
// Заполняем строковое представление
СтрокаТЗ.НаименованиеДляПоиска = Строка(СтрокаТЗ.Объект);
КонецЦикла;
// Теперь в запросе можно использовать ПОДОБНО напрямую к этой колонке
Запрос.Текст = "ВЫБРАТЬ * ИЗ &Т2 КАК Т2 ГДЕ Т2.НаименованиеДляПоиска ПОДОБНО &Поиск";
Многие разработчики жалуются, что при использовании временных таблиц из ТЗ Конструктор запроса "теряет" типы после закрытия. Выясним причину: описание типов во временных таблицах внутри Конструктора — это виртуальные метаданные. Они нужны только для того, чтобы вы могли удобно выбирать поля из списка. Они не сохраняются в тексте запроса.
Чтобы Конструктор всегда "знал" типы колонок вашей ТЗ, рекомендуется придерживаться следующих правил:
ТаблицыЗначений через Новый ОписаниеТипов. Платформа 1С версии 8.3 гораздо лучше подхватывает типы в рантайме, если они жестко заданы в объекте ТЗ.Объект и выбирать Наименование, Код и другие реквизиты.&Т2 таблица имела те же имена колонок и типы, что вы описали.Разберем несколько тонкостей, которые помогут избежать ошибок в будущем:
% означает любое количество произвольных символов, а _ (подчеркивание) — один произвольный символ. Если вам нужно найти сам символ процента, используйте конструкцию СПЕЦСИМВОЛ.ПОДОБНО "%Текст" (процент в начале) — это "убийца" производительности на больших таблицах, так как SQL-сервер не сможет использовать индексы. По возможности старайтесь использовать поиск по началу строки: "Текст%".ПОДОБНО нечувствителен к регистру (регистронезависим), но это зависит от настроек сопоставления (Collation) базы данных.Произвольный, запрос может вести себя непредсказуемо при попытке разыменования полей.Таким образом, мы рассмотрели основные подходы к фильтрации таблиц значений. Выбор конкретного метода зависит от ваших задач: для простых отчетов подойдет ВЫРАЗИТЬ, для высоконагруженных систем — ВНУТРЕННЕЕ СОЕДИНЕНИЕ, а для сложной предварительной обработки — подготовка строковых колонок в самой ТЗ.