Auto-découpage SQL Server de la valeur varchar en comparaison égale mais pas comme la comparaison

13

J'ai rencontré un comportement intéressant sur SQL Server (observé en 2005 et 2012) aujourd'hui que j'espérais que quelqu'un pourrait expliquer.

Une requête effectuant une comparaison à l'aide =d'un champ NVARCHAR a ignoré l'espace de fin dans la chaîne (ou a coupé automatiquement la valeur avant la comparaison), mais la même requête utilisant l' likeopérateur n'a pas ignoré l'espace. Le classement utilisé est Latin1_General_CI_AS en 2012.

Considérez ce SQL Fiddle: http://sqlfiddle.com/#!6/72262/4

Notez que l' likeopérateur ne renvoie pas de résultat pour la chaîne d'espace de fin, mais l' =opérateur le fait. Pourquoi est-ce?

Points bonus: je ne peux pas reproduire ceci sur un champ VARCHAR, j'aurais pensé qu'un espace serait géré de la même manière dans les deux types de données - est-ce vrai?

WT_W
la source
Je cherchais à écrire une contrainte de vérification qu'une chaîne a été coupée. J'ai trouvé une solution de contournement qui consiste à vérifier cela MyString+'x' = ltrim(rtrim(MyString))+'x'comme suggéré sur ce blog
default.kramer

Réponses:

15

Ma réponse initiale a suggéré que l'indicateur ANSI_PADDING réglé sur OFF pourrait être à l'origine de la différence de comportement. Cependant, c'est incorrect; cet indicateur n'a qu'un effet sur le stockage, mais pas sur la comparaison d'égalité.

La différence provient de l'implémentation par Microsoft du standard SQL . La norme stipule que lors de la vérification de l'égalité, les deux chaînes gauche et droite de l'opérateur d'égalité doivent être remplies pour avoir la même longueur . Cela explique les résultats suivants:

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

L'opérateur LIKE ne remplit pas ses opérandes. Il se comporte également différemment pour les types de colonnes VARCHARetNVARCHAR :

-- 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

Le comportement de l'opérateur LIKE pour le type ASCII est spécifique à SQL Server; pour le type Unicode, il est conforme ANSI.

Ralf
la source
4

SQL est né à une époque où la plupart des langages informatiques utilisaient des longueurs fixes pour chaque champ / variable. Le remplissage automatique des champs de texte avec des espaces supplémentaires faisait également partie de cette image. Pour aligner avec ce comportement, le type SQL CHAR d'origine a été explicitement défini pour son opérateur «=» pour ignorer les espaces de fin. (Si vous trouvez cela étrange, montrez-moi un cas convaincant où les espaces de fin ajoutés à un texte ont une réelle signification commerciale .)

Les types SQL CHAR ont évolué dans toutes sortes de directions depuis lors, mais il n'est pas inconcevable que certains types de données plus modernes héritent encore de certaines caractéristiques de leurs prédécesseurs historiques.

Erwin Smout
la source
"Montrez-moi un cas convaincant où les espaces de fin ajoutés à un texte ont une réelle signification commerciale" - en stockant des données importantes pour les espaces, telles que certaines sorties de console brutes et des fragments XML non dangereux.
Dai
1

Dans la documentation de LIKE (Transact-SQL) , Microsoft écrit (c'est moi qui souligne):

Correspondance de motifs à l'aide de LIKE

LIKE prend en charge la correspondance de modèles ASCII et la correspondance de modèles Unicode. Lorsque tous les arguments ... sont des types de données de caractères ASCII, une correspondance de modèle ASCII est effectuée. Si l'un des arguments est de type de données Unicode, tous les arguments sont convertis en Unicode et une correspondance de modèle Unicode est effectuée. Lorsque vous utilisez des données Unicode ... avec LIKE, les blancs de fin sont importants; cependant, pour les données non Unicode, les blancs de fin ne sont pas significatifs. Unicode LIKE est compatible avec la norme ISO. ASCII LIKE est compatible avec les versions antérieures de SQL Server.

Michel de Ruiter
la source