При разработке в среде 1С часто возникает задача сопоставления текстовых полей, содержащих иерархические структуры или пути файлов. Например, нам нужно связать две таблицы так, чтобы записи из второй таблицы соответствовали подчиненным путям из первой. Логичным решением кажется использование оператора ПОДОБНО (аналог SQL-оператора LIKE) с добавлением символа маски % в конец строки-родителя. Однако при попытке написать такое условие связи напрямую разработчики часто сталкиваются со сложными синтаксическими ошибками.
Давайте разберем по шагам, почему возникает ошибка компиляции запроса, как правильно экранировать кавычки в модулях 1С, почему стандарты разработки запрещают такое решение и как оптимизировать производительность СУБД при работе с большими объемами данных.
Предположим, у нас есть две таблицы значений: Тз1 и Тз2, переданные в запрос. Мы хотим соединить их по условию, при котором путь во второй таблице начинается с пути из первой таблицы. Схематично это должно выглядеть так:
Тз2.Путь ПОДОБНО Тз1.Путь + "%"
Попытка написать это в модуле 1С в виде строки запроса часто приводит к ошибкам. Посмотрим на некорректный пример кода, который часто пишут начинающие разработчики:
// НЕКОРРЕКТНЫЙ КОД - вызовет синтаксическую ошибку
Запрос.Текст =
"ВЫБРАТЬ
| Тз2.Путь КАК Путь,
| Тз1.Путь КАК ПутьРодитель
|ИЗ
| Тз1 КАК Тз1
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Тз2 КАК Тз2
| ПО Тз2.Путь ПОДОБНО Тз1.Путь" + "'%'" + "";
При компиляции такого кода платформа 1С выдаст ошибку разбора запроса. Проблема заключается в том, что оператор ПОДОБНО ожидает получить строку шаблона, но попытка «склеить» строку внутри кода 1С внешними средствами приводит к неверной структуре результирующего текста запроса, уходящего в СУБД.
Для решения этой проблемы необходимо использовать возможности конкатенации строк непосредственно на уровне языка запросов 1С (это поддерживается платформой, начиная с версии 8.3.6). Символ процента % должен быть оформлен как строковый литерал внутри самого запроса.
Правило компиляции строковых литералов в коде 1С гласит: любые двойные кавычки внутри строкового литерала должны быть продублированы (задвоены). Проанализируем правильный вариант написания:
// КОРРЕКТНЫЙ КОД - правильное экранирование кавычек
Запрос.Текст =
"ВЫБРАТЬ
| Тз2.Путь КАК Путь,
| Тз1.Путь КАК ПутьРодитель
|ИЗ
| Тз1 КАК Тз1
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Тз2 КАК Тз2
| ПО Тз2.Путь ПОДОБНО Тз1.Путь + ""%""";
Обратите внимание на конструкцию ""%"". При трансляции этого модуля платформа преобразует удвоенные кавычки в одну двойную кавычку. В СУБД уйдет чистый и корректный SQL-запрос со следующим условием соединения:
ПО Тз2.Путь ПОДОБНО Тз1.Путь + "%"
Несмотря на то, что приведенный выше синтаксис компилируется без ошибок, фирма «1С» в своих официальных методических рекомендациях (в частности, в стандарте #std726, посвященном особенностям использования оператора ПОДОБНО) крайне не рекомендует использовать динамическое сложение строк в шаблонах сравнения.
Давайте выясним причину этого запрета. Дело в кроссплатформенности и особенностях работы различных СУБД:
[...] (используемые для задания диапазонов символов), корректно интерпретируются только тогда, когда шаблон задан в виде константного строкового литерала. Если шаблон собирается динамически через выражение сложения (например, Тз1.Путь + "%"), СУБД может проигнорировать спецсимволы или аварийно завершить работу запроса.+ в специфичный для СУБД синтаксис (например, функция CONCAT() в MySQL/PostgreSQL или оператор || в Oracle). Однако при использовании внутри оператора ПОДОБНО такая трансляция усложняет построение оптимального плана запроса СУБД.Соединение двух таблиц по условию ПОДОБНО с динамическим шаблоном — это одна из самых опасных операций с точки зрения производительности реляционных баз данных. Рассмотрим подробнее, что происходит "под капотом" СУБД:
Индекс ПОДОБНО "Значение%" (где значение известно заранее). В нашем случае правая часть условия динамическая (Тз1.Путь). СУБД физически не может применить индекс к полю Тз2.Путь, так как шаблон поиска меняется для каждой строки.Если в ваших таблицах содержится всего по 100 записей, запрос отработает быстро. Но если объем данных вырастет хотя бы до нескольких десятков тысяч строк, время выполнения запроса увеличится экспоненциально (до нескольких минут или часов), намертво заблокировав таблицы и перегрузив процессор сервера СУБД.
Если перед нами стоит задача связать данные по иерархическому принципу, давайте проанализируем более надежные и быстродействующие подходы.
Если связываемые сущности являются элементами справочника 1С, откажитесь от текстового сравнения путей. Платформа 1С изначально оптимизирована для работы с иерархией. Используйте стандартную древовидную структуру (реквизит Родитель) и оператор запроса В ИЕРАРХИИ:
// Использование встроенного механизма иерархии справочников
ВЫБРАТЬ
СпрНоменклатура.Ссылка КАК Элемент,
СпрНоменклатура.Родитель КАК Родитель
ИЗ
Справочник.Номенклатура КАК СпрНоменклатура
ГДЕ
СпрНоменклатура.Ссылка В ИЕРАРХИИ(&РодительскаяГруппа)
Платформа преобразует такое условие в оптимальный SQL-код, использующий системные индексы, что обеспечит мгновенный выбор данных даже в базах с миллионами записей.
В случаях, когда вам нужно найти подчиненные элементы для одного конкретного известного пути, никогда не делайте конкатенацию внутри запроса. Подготовьте шаблон заранее в коде на встроенном языке и передайте его как параметр:
// Подготовка шаблона поиска в коде 1С
ШаблонПути = ПутьРодителя + "%";
Запрос.УстановитьПараметр("ШаблонПути", ШаблонПути);
// В тексте запроса:
// ГДЕ Тз2.Путь ПОДОБНО &ШаблонПути
Такой подход полностью соответствует стандартам разработки 1С, гарантирует корректную работу на любых СУБД и позволяет оптимизатору СУБД использовать индексы (так как шаблон является константой на момент выполнения запроса).
Если в реальных путях (именах папок, файлов или URL) могут содержаться спецсимволы СУБД (такие как процент %, нижнее подчеркивание _, квадратные скобки [ или ]), оператор ПОДОБНО может выдать непредсказуемый результат. Например, путь "Папка_1" СУБД воспримет как маску, где вместо "_" может быть любой символ.
Для предотвращения подобных ошибок используйте конструкцию СПЕЦСИМВОЛ совместно со стандартной функцией Библиотеки Стандартных Подсистем (БСП):
// Подготовка безопасного поискового выражения средствами БСП
СтрокаПоиска = "Папка_1/";
БезопасныйШаблон = ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(СтрокаПоиска) + "%";
Запрос.УстановитьПараметр("ШаблонПути", БезопасныйШаблон);
В тексте запроса используйте управляющее слово СПЕЦСИМВОЛ (или ESCAPE), указав символ экранирования (обычно это тильда ~):
ВЫБРАТЬ
Тз2.Путь КАК Путь
ИЗ
Тз2 КАК Тз2
ГДЕ
Тз2.Путь ПОДОБНО &ШаблонПути СПЕЦСИМВОЛ "~"
Функция БСП автоматически добавит символ экранирования перед всеми служебными знаками, гарантируя точное совпадение и защищая систему от сбоев.
Мы детально изучили синтаксис оператора ПОДОБНО в запросах 1С. Для исправления ошибки компиляции достаточно правильно использовать экранирование кавычек (""%"") при динамическом формировании текста запроса. Тем не менее, для высоконагруженных систем старайтесь заменять динамические сравнения по маске на параметризированные запросы, использование встроенных иерархий справочников или подготовку данных на стороне встроенного языка 1С.