Почему не работает сравнение строк в запросе 1С и как избежать ошибок при фильтрации?

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

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

Анализ логической ошибки в условии запроса

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


ВЫБРАТЬ
    DX_НоменклатураКонтрагентовСрезПоследних.СсылкаНаТовар,
    DX_НоменклатураКонтрагентовBackUpСрезПоследних.СсылкаНаТовар КАК СсылкаНаТовар1
ИЗ
    РегистрСведений.DX_НоменклатураКонтрагентов.СрезПоследних КАК DX_НоменклатураКонтрагентовСрезПоследних
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.DX_НоменклатураКонтрагентовBackUp.СрезПоследних КАК DX_НоменклатураКонтрагентовBackUpСрезПоследних
    ПО DX_НоменклатураКонтрагентовСрезПоследних.Контрагент = DX_НоменклатураКонтрагентовBackUpСрезПоследних.Контрагент
ГДЕ
    (DX_НоменклатураКонтрагентовBackUpСрезПоследних.СсылкаНаТовар = DX_НоменклатураКонтрагентовBackUpСрезПоследних.СсылкаНаТовар)

Выясним причину странного поведения этого запроса. Если мы внимательно посмотрим на секцию ГДЕ, то увидим, что поле СсылкаНаТовар сравнивается с самим собой из той же самой таблицы (бэкапа). В языке запросов 1С, как и в стандартном SQL, выражение Поле = Поле всегда будет возвращать Истина (за исключением случая, когда в поле содержится NULL, но об этом ниже). В результате фильтр фактически не работает, и мы получаем в выборке все записи, прошедшие через ЛЕВОЕ СОЕДИНЕНИЕ.

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


ГДЕ
    DX_НоменклатураКонтрагентовСрезПоследних.СсылкаНаТовар = DX_НоменклатураКонтрагентовBackUpСрезПоследних.СсылкаНаТовар

Особенности чувствительности к регистру в СУБД

Даже если в запросе нет опечаток, мы можем столкнуться с тем, что строки, которые визуально различаются, считаются системой идентичными. Разберем, почему это происходит. Поведение запроса при сравнении строк (операторы =, В ИЕРАРХИИ, ПОДОБНО) напрямую зависит от настроек используемой СУБД (MS SQL Server, PostgreSQL, Oracle или IBM DB2).

В большинстве инсталляций на базе MS SQL Server по умолчанию используется параметр Case Insensitive (регистронезависимость). Это означает, что для сервера базы данных строки «Товар», «ТОВАР» и «товар» — это одно и то же. Если ваша задача требует точного соответствия с учетом регистра, реализовать это только средствами языка запросов 1С будет крайне затруднительно. В таких случаях мы рекомендуем выполнять дополнительную проверку уже после получения результата запроса в коде на встроенном языке или использовать хэширование строк.

Проблема хвостовых пробелов: почему ПОДОБНО работает иначе?

Еще один важный нюанс — обработка пробелов в конце строки. Проанализируем ситуацию: в базе есть две строки — «Сервис» и «Сервис » (с двумя пробелами в конце). При использовании оператора «равно» (=) большинство СУБД проигнорируют эти пробелы и посчитают строки одинаковыми.

Однако, если мы заменим сравнение на оператор ПОДОБНО, результат изменится:

  1. Оператор = часто отсекает конечные пробелы при сравнении (зависит от настроек SQL-коллации).
  2. Оператор ПОДОБНО учитывает каждый символ, включая невидимые пробелы.

Поэтому, если ваш запрос находит записи по =, но не находит их при использовании ПОДОБНО "%Текст%", обязательно проверьте данные на наличие лишних символов в конце строки.

Сравнение строк неограниченной длины

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

Во-первых, такие поля нельзя напрямую использовать в условиях ГДЕ или в секции СГРУППИРОВАТЬ ПО. При попытке выполнить такой запрос платформа выдаст ошибку.

Во-вторых, чтобы сравнение заработало, нам необходимо привести строку к фиксированной длине с помощью функции ВЫРАЗИТЬ. Рассмотрим пример:


ВЫБРАТЬ
    Номенклатура.Наименование
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    ВЫРАЗИТЬ(Номенклатура.ДополнительноеОписание КАК СТРОКА(100)) = &НужноеОписание

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

Влияние NULL при левом соединении

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

Проанализируем поведение сравнения с NULL:

Если ваша цель — найти записи, которых нет в бэкапе, используйте конструкцию ЕСТЬ NULL:


ГДЕ
    DX_НоменклатураКонтрагентовBackUpСрезПоследних.СсылкаНаТовар ЕСТЬ NULL

Использование спецсимволов в операторе ПОДОБНО

Если вы сравниваете ссылки на товары, которые часто содержат URL-адреса, вы можете столкнуться с проблемой спецсимволов. В операторе ПОДОБНО символы % (любая последовательность), _ (один символ) и [] (диапазон) являются служебными.

Если ваша строка содержит, например, символ подчеркивания (https://site.ru/pulty_344), то в запросе 1С символ _ будет воспринят как команда «любой символ». Для корректного поиска таких строк используем конструкцию СПЕЦСИМВОЛ:


ГДЕ
    СсылкаНаТовар ПОДОБНО "https://site.ru/pulty#_344" СПЕЦСИМВОЛ "#"

Здесь мы указали, что символ, идущий после #, следует воспринимать как обычный текст, а не как служебную команду.

Итоги и рекомендации

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

  1. Всегда внимательно проверяйте псевдонимы таблиц в условиях ГДЕ, чтобы не сравнить поле само с собой.
  2. Учитывайте, что поиск по умолчанию обычно регистронезависим.
  3. При использовании ЛЕВОЕ СОЕДИНЕНИЕ всегда обрабатывайте возможные NULL значения.
  4. Для строк неограниченной длины обязательно используйте ВЫРАЗИТЬ с достаточным запасом длины.
  5. Помните, что = и ПОДОБНО по-разному относятся к пробелам в конце строки.

Соблюдение этих простых правил поможет вам избежать многочасовой отладки запросов и обеспечит корректность данных в ваших отчетах и обработках.

← На главную