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

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

При работе с программно созданными таблицами значений (ТЗ) и передачей их в запрос в качестве параметров программисты часто сталкиваются с проблемой фильтрации данных. Одной из самых распространенных задач является поиск по части строки с использованием оператора ПОДОБНО. Однако при попытке применить этот оператор к колонке, содержащей ссылки (например, СправочникСсылка), платформа выдает ошибку: "Неверные параметры ПОДОБНО".

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

Причина ошибки: Ссылки против Строк

Первое, что нам необходимо уяснить: оператор ПОДОБНО (LIKE) в языке запросов 1С работает исключительно со строковыми типами данных. Когда мы передаем в запрос таблицу, где в колонке Объект хранятся ссылки на элементы справочника, мы не можем напрямую написать ГДЕ Таблица.Объект ПОДОБНО &Поиск. Ссылка — это уникальный идентификатор (GUID), а не текст, который видит пользователь.

Для решения задачи нам нужно обратиться к текстовому реквизиту объекта — обычно это Наименование. Рассмотрим, как это сделать правильно, сохранив при этом возможность использования Конструктора запроса.

Способ 1: Использование функции ВЫРАЗИТЬ и разыменование полей

Если мы хотим быстро внести правки в существующий запрос, мы можем воспользоваться явным приведением типа. Это позволит Конструктору запроса понять, с каким объектом метаданных мы работаем, и даст возможность "развернуть" поля через точку.

Проанализируем пример кода запроса, где мы типизируем входящую колонку:


Запрос.Текст = 
"ВЫБРАТЬ
|    ВЫРАЗИТЬ(Т2.Объект КАК Справочник.пто_ОбъектыОС) КАК Объект
|ПОМЕСТИТЬ ВТ_Данные
|ИЗ
|    &Т2 КАК Т2
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|    ВТ_Данные.Объект КАК Объект
|ИЗ
|    ВТ_Данные КАК ВТ_Данные
|ГДЕ
|    ВТ_Данные.Объект.Наименование ПОДОБНО &Поиск";

В данном случае функция ВЫРАЗИТЬ сообщает системе, что в колонке Объект гарантированно находится ссылка конкретного типа. После этого обращение Объект.Наименование становится легитимным. Однако помните: обращение через точку в условии ГДЕ порождает неявное левое соединение в SQL-запросе, что может сказаться на производительности при больших объемах данных.

Способ 2: Соединение с таблицей справочника (оптимальный путь)

Более правильным и производительным способом считается явное соединение временной таблицы с реальной таблицей справочника из базы данных. Это позволяет избежать проблем с типизацией "на лету" и дает полный контроль над выбираемыми полями.

Рассмотрим пошагово этот алгоритм:

  1. Помещаем исходную ТЗ во временную таблицу.
  2. Соединяем её по ссылке с основной таблицей справочника.
  3. В секции ГДЕ накладываем условие на наименование из основной таблицы.

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|    Т1.Объект КАК СсылкаНаОбъект
|ПОМЕСТИТЬ ВТ_Исходник
|ИЗ
|    &Таблица1 КАК Т1
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|    Т1.СсылкаНаОбъект КАК Объект,
|    СпрОбъекты.Наименование КАК Наименование
|ИЗ
|    ВТ_Исходник КАК Т1
|    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.пто_ОбъектыОС КАК СпрОбъекты
|    ПО Т1.СсылкаНаОбъект = СпрОбъекты.Ссылка
|ГДЕ
|    СпрОбъекты.Наименование ПОДОБНО &Поиск";

Запрос.УстановитьПараметр("Таблица1", Т1);
Запрос.УстановитьПараметр("Поиск", "%Система учета%");
Результат = Запрос.Выполнить().Выгрузить();

Важный момент: Если в вашей ТЗ могут быть пустые ссылки или ссылки разных типов, используйте ЛЕВОЕ СОЕДИНЕНИЕ и функцию ЕСТЬNULL для обработки пустых значений наименования.

Способ 3: Предварительная подготовка ТЗ в коде 1С

Иногда проще подготовить данные до того, как они попадут в запрос. Мы можем добавить в таблицу значений отдельную строковую колонку и заполнить её наименованиями объектов. Тогда в запросе нам не придется делать никаких соединений или обращений через точку.


// Подготовим описание типов для строковой колонки
КвалификаторСтроки = Новый КвалификаторыСтроки(150);
ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка", , КвалификаторСтроки);

// Добавим колонку для поиска
Т2.Колонки.Добавить("НаименованиеДляПоиска", ОписаниеТипаСтрока);

Для Каждого СтрокаТЗ Из Т2 Цикл
    // Заполняем строковое представление
    СтрокаТЗ.НаименованиеДляПоиска = Строка(СтрокаТЗ.Объект); 
КонецЦикла;

// Теперь в запросе можно использовать ПОДОБНО напрямую к этой колонке
Запрос.Текст = "ВЫБРАТЬ * ИЗ &Т2 КАК Т2 ГДЕ Т2.НаименованиеДляПоиска ПОДОБНО &Поиск";

Работа с Конструктором запроса и временными таблицами

Многие разработчики жалуются, что при использовании временных таблиц из ТЗ Конструктор запроса "теряет" типы после закрытия. Выясним причину: описание типов во временных таблицах внутри Конструктора — это виртуальные метаданные. Они нужны только для того, чтобы вы могли удобно выбирать поля из списка. Они не сохраняются в тексте запроса.

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

Технические нюансы использования ПОДОБНО

Разберем несколько тонкостей, которые помогут избежать ошибок в будущем:

  1. Маски поиска: Символ % означает любое количество произвольных символов, а _ (подчеркивание) — один произвольный символ. Если вам нужно найти сам символ процента, используйте конструкцию СПЕЦСИМВОЛ.
  2. Производительность: Условие ПОДОБНО "%Текст" (процент в начале) — это "убийца" производительности на больших таблицах, так как SQL-сервер не сможет использовать индексы. По возможности старайтесь использовать поиск по началу строки: "Текст%".
  3. Чувствительность к регистру: В большинстве типовых конфигураций 1С на SQL-сервере поиск через ПОДОБНО нечувствителен к регистру (регистронезависим), но это зависит от настроек сопоставления (Collation) базы данных.
  4. Типизация в ТЗ: Если вы передаете таблицу в запрос, крайне желательно, чтобы колонка была типизирована одним типом. Если колонка имеет тип Произвольный, запрос может вести себя непредсказуемо при попытке разыменования полей.

Таким образом, мы рассмотрели основные подходы к фильтрации таблиц значений. Выбор конкретного метода зависит от ваших задач: для простых отчетов подойдет ВЫРАЗИТЬ, для высоконагруженных систем — ВНУТРЕННЕЕ СОЕДИНЕНИЕ, а для сложной предварительной обработки — подготовка строковых колонок в самой ТЗ.

← На главную