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

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

При решении задач сопоставления данных разработчики нередко сталкиваются с необходимостью объединить таблицы не по точному равенству ссылок или чисел, а по вхождению одной строки в другую. Например, когда требуется найти документы по фрагменту номера или даты, указанному пользователем в текстовом реквизите Комментарий.

Рассмотрим, можно ли использовать конструкцию ПОДОБНО в секции ПО при соединении таблиц, с какими ограничениями платформы 1С при этом можно столкнуться и как правильно решить задачу сопоставления данных.

Возможность использования ПОДОБНО в условиях соединения

Язык запросов 1С:Предприятия полностью поддерживает оператор ПОДОБНО внутри секции ПО при выполнении левого, правого или полного соединения. В условии можно выполнять конкатенацию строковых выражений с помощью оператора + и спецсимволов шаблона % или _.

Посмотрим на рабочий пример простого соединения по вхождению подстроки:


ВЫБРАТЬ
    "конверс" КАК Поле1
ПОМЕСТИТЬ ВТ_Соединение
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ПлатежноеПоручение.НазначениеПлатежа,
    ВТ_Соединение.Поле1
ИЗ
    Документ.ПлатежноеПоручениеВходящее КАК ПлатежноеПоручение
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соединение КАК ВТ_Соединение
        ПО ПлатежноеПоручение.НазначениеПлатежа ПОДОБНО "%" + ВТ_Соединение.Поле1 + "%"

Несмотря на то что синтаксически платформа допускает такие конструкции, на практике попытка соединить произвольные таблицы часто завершается ошибкой «Неверные параметры» или ошибками трансляции запроса в СУБД. Разберем ключевые причины этих ошибок.

Ограничения платформы: почему запрос выдает ошибку

  1. Использование псевдофункции ПРЕДСТАВЛЕНИЕ:

    Псевдофункции ПРЕДСТАВЛЕНИЕ() и ПРЕДСТАВЛЕНИЕССЫЛКИ() обрабатываются платформой на клиенте или сервере приложений уже после выполнения основного SQL-запроса к базе данных. По этой причине их категорически нельзя использовать в секциях ГДЕ, ПО, ИМЕЮЩИЕ или внутри строковых выражений и конкатенаций.

  2. Невозможность преобразования типов Дата и Число в Строку внутри запроса:

    В языке запросов 1С функция ВЫРАЗИТЬ() предназначена только для уточнения составных ссылочных типов и ограничения максимальной длины строк. Преобразовать значение типа Дата или Число в Строку средствами чистого запроса невозможно. Функции извлечения частей даты (ГОД(), МЕСЯЦ(), ДЕНЬ()) возвращают числовые значения, которые также нельзя сложить со строкой через +.

  3. Строки неограниченной длины:

    Реквизит Комментарий практически во всех типовых объектах имеет тип Строка неограниченной длины. В запросах 1С строки неограниченной длины запрещено напрямую использовать в условиях соединения и операциях конкатенации. Их обязательно нужно приводить к фиксированной длине с помощью функции ПОДСТРОКА(), например: ПОДСТРОКА(Документ.Комментарий, 1, 1000).

  4. Критическое падение производительности:

    Условие вида ПОДОБНО "%" + Поле + "%" полностью исключает использование индексов таблиц СУБД. В результате соединение выполняется методом полного сканирования и декартова перебора (Nested Loop), что на реальных базах данных приводит к многоминутным зависаниям и блокировкам.

Варианты правильного решения задачи

Проанализируем практические способы реализации поиска и сопоставления документов, когда исходные данные содержат даты и номера в строковом комментарии.

Способ 1. Предварительная подготовка данных во встроенном языке (Таблица Значений)

Если сопоставление выполняется в рамках внешнего отчета или обработки, наиболее надежный подход — сформировать нужные строковые представления даты и номера на встроенном языке 1С, передать их в запрос в виде таблицы значений и соединить с ограничением длины через ПОДСТРОКА.

Разберем по шагам реализацию этого способа:


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

ТаблицаИсточников = ЗапросИсточников.Выполнить().Выгрузить();

// 2. Добавляем колонки с готовыми строковыми представлениями
ТаблицаИсточников.Колонки.Добавить("СтрокаНомера", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(30)));
ТаблицаИсточников.Колонки.Добавить("СтрокаДаты", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(20)));

Для Каждого Стр Из ТаблицаИсточников Цикл
    // Преобразуем дату в строковый формат, как его обычно вводят пользователи
    Стр.СтрокаДаты = Формат(Стр.Дата, "ДФ=dd.MM.yyyy");
    // Удаляем лидирующие нули из номера при необходимости
    Стр.СтрокаНомера = СокрЛП(Стр.Номер);
КонецЦикла;

// 3. Передаем подготовленную таблицу во второй запрос
ЗапросСопоставления = Новый Запрос;
ЗапросСопоставления.Текст = 
    "ВЫБРАТЬ
    |   ТЗ.Документ КАК ИсходныйДокумент,
    |   ТЗ.СтрокаНомера КАК СтрокаНомера,
    |   ТЗ.СтрокаДаты КАК СтрокаДаты
    |ПОМЕСТИТЬ ВТ_Источники
    |ИЗ
    |   &ТаблицаИсточников КАК ТЗ
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |   ВТ_Источники.ИсходныйДокумент,
    |   Поступление.Ссылка КАК ДокументПоступления
    |ИЗ
    |   ВТ_Источники КАК ВТ_Источники
    |   ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваровУслуг КАК Поступление
    |       ПО ПОДСТРОКА(Поступление.Комментарий, 1, 500) ПОДОБНО ""%"" + ВТ_Источники.СтрокаНомера + ""%""
    |           И ПОДСТРОКА(Поступление.Комментарий, 1, 500) ПОДОБНО ""%"" + ВТ_Источники.СтрокаДаты + ""%""";

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

Способ 2. Постобработка выборки в коде 1С

Если объем документов в базе велик, выполнение соединения через ПОДОБНО в СУБД создаст чрезмерную нагрузку. В этом случае эффективнее получить обе выборки простыми быстрыми запросами и выполнить сопоставление в памяти сервера с помощью функций СтрНайти().


// Выбираем только те документы, где комментарий не пустой
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Поступление.Ссылка КАК Ссылка,
    |   Поступление.Комментарий КАК Комментарий
    |ИЗ
    |   Документ.ПоступлениеТоваровУслуг КАК Поступление
    |ГДЕ
    |   Поступление.Комментарий <> """"";

ВыборкаПоступлений = Запрос.Выполнить().Выгрузить();

// Сопоставляем в цикле по списку исходных документов
Для Каждого СтрОприходование Из ТаблицаИсточников Цикл
    СтрокаПоискаНомера = СтрОприходование.СтрокаНомера;
    СтрокаПоискаДаты = СтрОприходование.СтрокаДаты;
    
    Для Каждого СтрПоступление Из ВыборкаПоступлений Цикл
        Если СтрНайти(СтрПоступление.Комментарий, СтрокаПоискаНомера) > 0 
            И СтрНайти(СтрПоступление.Комментарий, СтрокаПоискаДаты) > 0 Тогда
            
            // Связка найдена, фиксируем соответствие
            Прервать;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Способ 3. Архитектурное решение (нормализация данных)

Для исключения регулярных сложностей с неточным поиском по текстовым строкам рекомендуется связать документы на уровне структуры метаданных:

  1. Заполнять стандартный реквизит ДокументОснование в документе-приемнике.
  2. Использовать подчиненный регистр сведений или критерий отбора для фиксации связей между объектами.

Такой подход позволяет строить запросы по прямому равенству ссылочных полей, что гарантирует максимальную производительность СУБД и исключает ошибки сопоставления.

← На главную