caractères Unicode causant des problèmes dans SQL Server 2005 comparaison de chaînes
-
21-09-2019 - |
Question
Cette requête:
select *
from op.tag
where tag = 'fussball'
Renvoie un résultat qui a une valeur de colonne d'étiquette de « Fußball ». La colonne "tag" est définie comme nvarchar (150).
Même si je comprends qu'ils sont mots grammaticalement similaires, peut-on expliquer et de défendre ce comportement? Je suppose qu'il est en rapport avec les mêmes paramètres de classement qui vous permettent de changer la casse sur une colonne / table, mais qui voudrait ce comportement? Une contrainte unique sur la colonne provoque également l'échec sur inserts d'une valeur lorsque l'autre existe en raison d'une violation de contrainte. Comment puis-je désactiver cette?
Suivi question de point de bonus. Expliquez pourquoi cette requête ne renvoie aucune ligne:
select 1
where 'fußball' = 'fussball'
Question bonus (réponse?): @ScottCher me fit remarquer en privé que cela est dû à la chaîne « Fußball » être traité comme un varchar. Cette requête ne renvoie un résultat:
select 1
where 'fußball' = cast('fussball' as nvarchar)
Mais là encore, celui-ci ne fonctionne pas:
select 1
where cast('fußball' as varchar) = cast('fussball' as varchar)
Je suis confus.
La solution
Je suppose que l'ensemble de classement Unicode pour votre connexion / table / base de données indique que les art == ß. Ce dernier comportement serait parce qu'il est sur un chemin rapide défectueux, ou peut-être fait une comparaison binaire, ou peut-être que vous n'êtes pas passer dans le ß dans le bon codage (je suis d'accord, il est stupide).
http://unicode.org/reports/tr10/#Searching mentionne que U + 00DF est-tubé spéciale. Voici un extrait perspicace:
recherche en langage sensible et correspondant sont étroitement liés à collation. Les chaînes comme comparer égale à un certain niveau de résistance sont ceux qui devrait être utilisée lorsque faire correspondant sensible à la langue. Pour par exemple, à une force primaire, « ß » correspondrait à contre « art », selon l'UCA, et « aa » correspondrait à « å » dans un Tailoring danoise de l'UCA.
Autres conseils
SELECT ne retourner une rangée avec Latin1_General_CI_AS de classement (de SQL2000).
Finalité pas avec la collation Latin1_General_BIN.
Vous pouvez assigner une colonne de table une collation en utilisant le COLLATE
Vous pouvez également comparer les chaînes avec un classement spécifique en utilisant la syntaxe
string1 = string2 COLLATE < collation >
Quelques réponses d'aide - pas au complet à votre question, mais peut-être utile:
Si vous essayez:
SELECT 1 WHERE N'fußball' = N'fussball'
vous obtiendrez « 1 » - lorsque vous utilisez le « N » pour signifier Unicode, les deux chaînes sont considérés comme identiques. - Pourquoi c'est le cas, je ne sais pas (encore)
Pour classement par défaut pour un serveur, utilisez
SELECT SERVERPROPERTY('Collation')
Pour la collation d'une colonne donnée dans une base de données, utilisez cette requête:
SELECT
name 'Column Name',
OBJECT_NAME(object_id) 'Table Name',
collation_name
FROM sys.columns
WHERE object_ID = object_ID('your-table-name')
AND name = 'your-column-name'
Ce n'est pas une réponse qui explique le comportement, mais il peut être pertinent:
cette question , j'ai appris que en utilisant le classement de
Latin1_General_Bin
évitera la plupart des bizarreries de classement.
Question bonus (réponse?): @ScottCher m'a fait remarquer en privé que cette est due à la chaîne littérale « Fußball » traité comme un varchar. Cette requête ne renvoie un résultat:
select 1 where 'fußball' =
cast('fussball' as nvarchar)
Ici, vous avez affaire avec les règles de priorité de type de données SQL Server, comme indiqué dans