При написании запросов в системе «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С будет крайне затруднительно. В таких случаях мы рекомендуем выполнять дополнительную проверку уже после получения результата запроса в коде на встроенном языке или использовать хэширование строк.
Еще один важный нюанс — обработка пробелов в конце строки. Проанализируем ситуацию: в базе есть две строки — «Сервис» и «Сервис » (с двумя пробелами в конце). При использовании оператора «равно» (=) большинство СУБД проигнорируют эти пробелы и посчитают строки одинаковыми.
Однако, если мы заменим сравнение на оператор ПОДОБНО, результат изменится:
= часто отсекает конечные пробелы при сравнении (зависит от настроек SQL-коллации).ПОДОБНО учитывает каждый символ, включая невидимые пробелы.Поэтому, если ваш запрос находит записи по =, но не находит их при использовании ПОДОБНО "%Текст%", обязательно проверьте данные на наличие лишних символов в конце строки.
В системе 1С существует ограничение на работу с полями типа Строка неограниченной длины в запросах. Посмотрим на основные правила:
Во-первых, такие поля нельзя напрямую использовать в условиях ГДЕ или в секции СГРУППИРОВАТЬ ПО. При попытке выполнить такой запрос платформа выдаст ошибку.
Во-вторых, чтобы сравнение заработало, нам необходимо привести строку к фиксированной длине с помощью функции ВЫРАЗИТЬ. Рассмотрим пример:
ВЫБРАТЬ
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
ВЫРАЗИТЬ(Номенклатура.ДополнительноеОписание КАК СТРОКА(100)) = &НужноеОписание
Важно помнить: если реальный текст в поле ДополнительноеОписание длиннее 100 символов, функция ВЫРАЗИТЬ его обрежет. Сравнение будет производиться только по первым 100 символам, что может привести к ложноположительным результатам.
Когда мы используем ЛЕВОЕ СОЕДИНЕНИЕ, как в примере из темы форума, мы всегда должны помнить о значении NULL. Если во второй таблице (бэкапе) не найдется соответствующая запись, все поля этой таблицы в результате запроса примут значение NULL.
Проанализируем поведение сравнения с NULL:
NULL (например, NULL = "" или NULL = "Текст") дает результат Ложь.NULL = NULL не дает Истину в классической логике SQL.Если ваша цель — найти записи, которых нет в бэкапе, используйте конструкцию ЕСТЬ NULL:
ГДЕ
DX_НоменклатураКонтрагентовBackUpСрезПоследних.СсылкаНаТовар ЕСТЬ NULL
Если вы сравниваете ссылки на товары, которые часто содержат URL-адреса, вы можете столкнуться с проблемой спецсимволов. В операторе ПОДОБНО символы % (любая последовательность), _ (один символ) и [] (диапазон) являются служебными.
Если ваша строка содержит, например, символ подчеркивания (https://site.ru/pulty_344), то в запросе 1С символ _ будет воспринят как команда «любой символ». Для корректного поиска таких строк используем конструкцию СПЕЦСИМВОЛ:
ГДЕ
СсылкаНаТовар ПОДОБНО "https://site.ru/pulty#_344" СПЕЦСИМВОЛ "#"
Здесь мы указали, что символ, идущий после #, следует воспринимать как обычный текст, а не как служебную команду.
Для того чтобы сравнение строк в ваших запросах всегда работало предсказуемо, мы рекомендуем придерживаться следующих правил:
ГДЕ, чтобы не сравнить поле само с собой.ЛЕВОЕ СОЕДИНЕНИЕ всегда обрабатывайте возможные NULL значения.ВЫРАЗИТЬ с достаточным запасом длины.= и ПОДОБНО по-разному относятся к пробелам в конце строки.Соблюдение этих простых правил поможет вам избежать многочасовой отладки запросов и обеспечит корректность данных в ваших отчетах и обработках.