SQL Server автоматически обрезает значение varchar в равном сравнении, но не в сравнении

13

Сегодня я столкнулся с некоторым интересным поведением на SQL Server (наблюдавшемся в 2005 и 2012 годах), которое, я надеялся, кто-нибудь сможет объяснить.

Запрос, выполняющий сравнение с =использованием поля NVARCHAR, игнорировал конечный пробел в строке (или автоматически обрезал значение перед сравнением), но тот же запрос с использованием likeоператора не игнорировал этот пробел. Используемая сортировка - Latin1_General_CI_AS в 2012 году.

Рассмотрим эту скрипту SQL: http://sqlfiddle.com/#!6/72262/4

Обратите внимание, что likeоператор не возвращает результат для строки завершающего пробела, но =оператор возвращает . Почему это?

Бонусные баллы: я не могу повторить это в поле VARCHAR, я бы подумал, что пробел будет обрабатываться одинаково в обоих типах данных - это правда?

WT_W
источник
Я хотел написать проверочное ограничение, чтобы строка была обрезана. Я нашел обходной путь, который должен проверить это, MyString+'x' = ltrim(rtrim(MyString))+'x'как предложено в этом блоге
default.kramer

Ответы:

15

Мой первоначальный ответ предполагал, что флаг ANSI_PADDING, установленный в OFF, может быть виноват в разнице в поведении. Однако это неверно; этот флаг влияет только на хранилище, но не на сравнение равенства.

Разница заключается в реализации Microsoft стандарта SQL . Стандарт гласит, что при проверке на равенство обе строки слева и справа от оператора равенства должны иметь одинаковую длину . Это объясняет следующие результаты:

insert into test_padding (varchar_clmn, nvarchar_clmn) values ('space ', 'nspace ')
go
-- equality for varchar column
select count(*) from test_padding where varchar_clmn = 'space' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn = 'space    ' --returns 1
-- equality for nvarchar column
select count(*) from test_padding where nvarchar_clmn = 'nspace' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn = 'nspace    ' --returns 1

Оператор LIKE не дополняет свои операнды. Он также ведет себя по- разному для VARCHARи NVARCHARтипов столбцов :

-- likeness for varchar column
select count(*) from test_padding where varchar_clmn like 'space' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space ' -- returns 1
select count(*) from test_padding where varchar_clmn like 'space    ' -- returns 0
-- likeness for nvarchar column
select count(*) from test_padding where nvarchar_clmn like 'nspace' -- returns 0
select count(*) from test_padding where nvarchar_clmn like 'nspace ' -- returns 1
select count(*) from test_padding where nvarchar_clmn like 'nspace    ' -- returns 0

Поведение оператора LIKE для типа ASCII зависит от SQL Server; для типа Unicode это ANSI-совместимый.

Ralf
источник
4

SQL родился в эпоху, когда большинство языков обработки данных использовали фиксированные длины для каждого поля / переменной. Автоматическое заполнение текстовых полей дополнительными пробелами также было частью этой картины. Чтобы соответствовать этому поведению, исходный тип SQL CHAR был явно определен для его оператора '=', чтобы игнорировать конечные пробелы. (Если вы находите это странным, покажите мне убедительный случай, когда конечные пробелы, добавленные к тексту, имеют реальное реальное деловое значение .)

С тех пор типы SQL CHAR развивались во всех направлениях, но не исключено, что некоторые более современные типы данных все еще унаследовали некоторые характеристики от своих исторических предшественников.

Эрвин Смут
источник
«Покажите мне убедительный случай, когда конечные пробелы, добавленные к тексту, имеют реальное реальное деловое значение» - хранение значимых для пробелов данных, таких как некоторые необработанные выходные данные консоли и небезопасные фрагменты XML.
Дай
1

В документации для LIKE (Transact-SQL) Microsoft пишет (выделено мое):

Сопоставление с шаблоном с помощью LIKE

LIKE поддерживает сопоставление с ASCII и Unicode. Когда все аргументы ... являются символьными типами данных ASCII, выполняется сопоставление с шаблоном ASCII. Если какой-либо из аргументов имеет тип данных Unicode, все аргументы преобразуются в Unicode и выполняется сопоставление с шаблоном Unicode. Когда вы используете данные Unicode ... с LIKE, конечные пробелы имеют большое значение; однако для данных не в Юникоде конечные пробелы не имеют значения. Unicode LIKE совместим со стандартом ISO. ASCII LIKE совместим с более ранними версиями SQL Server.

Мишель де Рюитер
источник