Автоматична обробка значення Varchar у SQL Server у рівних порівняннях, але не схожа на порівняння


13

Сьогодні я натрапив на цікаву поведінку на SQL Server (спостерігався у 2005 та 2012 роках), що сподівався, що хтось зможе пояснити.

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

Розглянемо цей скрипт SQL: http://sqlfiddle.com/#!6/72262/4

Зауважте, що likeоператор не повертає результат для рядка пробілу, але =оператор робить. Чому це?

Бонусні бали: я не в змозі повторити це на полі VARCHAR, я б подумав, що простір обробляється однаково в обох типах даних - це правда?


Я шукав написати обмеження чека, що обрізана струна. Я знайшов вирішення цього питання, щоб перевірити, 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.


4

SQL народився в епоху, коли більшість мов обробки даних використовували фіксовану довжину для кожного поля / змінної. Автоматичне набивання текстових полів із додатковими пробілами також було частиною цього малюнка. Для вирівнювання такої поведінки оригінальний тип SQL CHAR був чітко визначений для його оператора '=' для ігнорування проміжних пробілів. (Якщо вам це здається дивним, покажіть мені переконливий випадок, коли пробіли, додані до тексту, мають справжнє ділове значення .)

З тих пір типи SQL CHAR еволюціонували у всіляких напрямках, але немислимо, що деякі більш сучасні типи даних все ще успадкували деякі характеристики від своїх попередніх попередників.


"покажіть мені переконливий випадок, коли пробіли, додані до тексту, мають реальне ділове значення" - зберігання значущих пробілів даних, таких як певні вихідні консолі та попередньо небезпечні фрагменти XML.
Дай

1

У документації для LIKE (Transact-SQL) Microsoft пише (міна акценту):

Узгодження шаблону за допомогою LIKE

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.