Предложение SQL WHERE для сопоставления значений с конечными пробелами
В SQL Server 2008 у меня есть таблица с именем Zone
с столбцом ZoneReference varchar(50) not null
в качестве первичного ключа.
Если я запустил следующий запрос:
select '"' + ZoneReference + '"' as QuotedZoneReference
from Zone
where ZoneReference = 'WF11XU'
Получаю следующий результат:
"WF11XU "
Обратите внимание на конечное пространство.
Как это возможно? Если в этой строке есть конечное пространство, я ожидаю вернуть результаты нуль, поэтому я предполагаю, что это будет нечто, что SQL Server Management Studio отображает странно.
В вызове кода С# zoneReference.Trim()
удаляется его, указывая, что это какой-то символ пробела.
Может ли кто-нибудь помочь?
Ответы
Ответ 1
Это ожидаемый результат: в 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.
Источник
Ответ 2
Промежуточные пробелы не всегда игнорируются.
Сегодня я испытал этот вопрос. В моей таблице были столбцы NCHAR и соединялись с данными VARCHAR.
Поскольку данные в таблице были не такими широкими, как поле, конечные пробелы были автоматически добавлены SQL Server.
У меня была ITVF (встроенная функция с табличной оценкой), которая принимала параметры varchar.
Параметры использовались в JOIN для таблицы с полями NCHAR.
Соединения не удались, потому что данные, переданные функции, не имели завершающих пробелов, но данные в таблице выполнялись. Почему это было?
Я сработал на DEC TYPE PRECEDENCE. (См. http://technet.microsoft.com/en-us/library/ms190309.aspx)
При сравнении строк разных типов тип более низкого приоритета перед сравнением преобразуется в более высокий тип приоритета. Поэтому параметры VARCHAR были преобразованы в NCHAR. Сравнение NCHAR сравнивалось, и, по-видимому, пространства были значительными.
Как я это исправил? Я изменил определение функции для использования параметров NVARCHAR, которые имеют более высокий приоритет, чем NCHAR. Теперь NCHAR были автоматически изменены SQL Server в NVARCHAR, а конечные пробелы были проигнорированы.
Почему я просто не выполнял RTRIM? Тестирование показало, что RTRIM убил производительность, предотвращая оптимизации JOIN, которые SQL Server использовал бы в противном случае.
Почему бы не изменить тип данных таблицы? Таблицы уже установлены на клиентских сайтах, и они не хотят запускать сценарии обслуживания (время + деньги для оплаты DBAs) или дают нам доступ к их машинам (понятно).
Ответ 3
Да, Марк прав. Запустите следующий 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
Но утверждение о "подобном" утверждении, похоже, не работает в приведенном выше примере. Выход:
(1 row(s) affected)
-----------------
"james "
(1 row(s) affected)
-----------------
"james "
(1 row(s) affected)
EDIT:
Чтобы заставить его работать, вы можете положить конец:
and name <> rtrim(ltrim(name))
Уродливый, хотя.
EDIT2:
Учитывая комментарии abovem, будет работать следующее:
select '"' + name + '"' from #temp where 'james' like name
Ответ 4
попробовать
select Replace('"' + ZoneReference + '"'," ", "") as QuotedZoneReference from Zone where ZoneReference = 'WF11XU'