Предложение SQL WHERE сопоставляет значения с конечными пробелами - PullRequest
43 голосов
/ 12 ноября 2010

В SQL Server 2008 у меня есть таблица с именем Zone со столбцом ZoneReference varchar(50) not null в качестве первичного ключа.

Если я запускаю следующий запрос:

select '"' + ZoneReference + '"' as QuotedZoneReference
from Zone
where ZoneReference = 'WF11XU'

Я получаюследующий результат:

"WF11XU "

Обратите внимание на завершающий пробел.

Как это возможно?Если в этой строке действительно есть конечный пробел, то я ожидаю, что вернет ноль результатов, поэтому я предполагаю, что SQL Server Management Studio отображает что-то еще странное.

В коде C # вызов zoneReference.Trim() удаляет его, предполагая, что это какой-то символ пробела.

Кто-нибудь может помочь?

Ответы [ 4 ]

65 голосов
/ 12 ноября 2010

Это ожидаемый результат: в SQL Server оператор = игнорирует завершающие пробелы при выполнении сравнения.

SQL Server следует спецификации ANSI / ISO SQL-92 (Раздел 8.2, Общие правила № 3), как сравнивать строки с пробелами. Стандарт ANSI требует заполнения для строк символов, используемых в сравнениях, чтобы их длина соответствовала перед сравнением. Заполнение напрямую влияет на семантику предикатов предложения WHERE и HAVING и другие сравнения строк Transact-SQL. Например, Transact-SQL считает, что строки 'abc' и 'abc' эквивалентны для большинства операций сравнения.

Единственным исключением из этого правила является предикат LIKE. Когда правая часть выражения предиката LIKE содержит значение с завершающим пробелом, SQL Server не дополняет два значения одинаковой длиной до того, как произойдет сравнение. Поскольку цель предиката LIKE по определению состоит в том, чтобы облегчить поиск по шаблону, а не в простых тестах на равенство строк, это не нарушает раздел спецификации ANSI SQL-92, упомянутый ранее.

Источник

6 голосов
/ 11 ноября 2013

Пробелы в конце не всегда игнорируются. Я столкнулся с этой проблемой сегодня.Моя таблица имела столбцы NCHAR и была присоединена к данным VARCHAR.Поскольку данные в таблице были не такими широкими, как ее поле, SQL Server автоматически добавлял конечные пробелы.

У меня была ITVF (встроенная табличная функция), которая принимала параметры varchar.Параметры использовались в соединении с таблицей с полями NCHAR.

Соединения не были выполнены, поскольку данные, передаваемые в функцию, не имели конечных пробелов, а данные в таблице -.Почему это было?

Меня смутило ДЕЙСТВИЕ ТИПА ДАННЫХ.(См. http://technet.microsoft.com/en-us/library/ms190309.aspx)

. При сравнении строк различных типов, тип с более низким приоритетом перед сравнением преобразуется в тип с более высоким приоритетом. Поэтому мои параметры VARCHAR были преобразованы в NCHAR.и, видимо, пробелы были значительными.

Как я это исправил? Я изменил определение функции, чтобы использовать параметры NVARCHAR, которые имеют более высокий приоритет, чем NCHAR. Теперь SQL Server автоматически заменяет NCHAR на NVARCHAR изавершающие пробелы были проигнорированы.

Почему я просто не выполнил RTRIM? Тестирование показало, что RTRIM убил производительность, предотвращая оптимизацию JOIN, которую SQL Server мог бы использовать в противном случае.изменить тип данных таблицы? Таблицы уже установлены на сайтах клиентов, и они не хотят запускать сценарии обслуживания (время + деньги, чтобы платить администраторам баз данных) или предоставлять нам доступ к их машинам (понятно).

3 голосов
/ 12 ноября 2010

Да, Марк прав.Запустите следующий SQL:

create table #temp (name varchar(15))
insert into #temp values ('james ')
select '"' + name + '"' from #temp where name ='james'
select '"' + name + '"' from #temp where name like 'james'
drop table #temp

Но утверждение об операторе like похоже не работает в приведенном выше примере.Вывод:

(1 row(s) affected)

-----------------
"james "

(1 row(s) affected)


-----------------
"james "

(1 row(s) affected)

РЕДАКТИРОВАТЬ: Чтобы заставить его работать, вы могли бы положить в конце:

and name <> rtrim(ltrim(name))

Хотя уродливо.

EDIT2: Учитывая комментарии выше, будет работать следующее:

select '"' + name + '"' from #temp where 'james' like name
0 голосов
/ 12 ноября 2010

попробуй

    select Replace('"' + ZoneReference + '"'," ", "") as QuotedZoneReference from Zone where ZoneReference = 'WF11XU'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...