web-dev-qa-db-fra.com

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

Je suis tombé sur 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 de = sur 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'opérateur like 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'opérateur like ne renvoie pas de résultat pour la chaîne d'espace de fin, mais le = l'opérateur le fait. Pourquoi est-ce?

Points bonus: je ne suis pas en mesure de reproduire cela 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?

13
WT_W

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

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

15
Ralf

SQL est né à une époque où la plupart des langages de traitement de données 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 véritable sens commercial réel.)

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.

4
Erwin Smout

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 ASCII correspondance de modèle et correspondance de modèle Unicode. Lorsque tous les arguments ... sont ASCII types de données de caractères, ASCII une correspondance de modèle est effectuée. Si l'un des arguments est de type 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.

1
Michel de Ruiter