Le codage UCS-2 est toujours de 2 octets par caractère et a une plage de 0 à 65535 (0x0000 - 0xFFFF). UTF-16 (indépendamment de Big Endian ou Little Endian) a une plage de 0 - 1114111 (0x0000 - 0x10FFFF). La plage 0 - 65535 / 0x0000 - 0xFFFF de UTF-16 est de 2 octets par caractère tandis que la plage au-dessus de 65536 / 0xFFFF est de 4 octets par caractère.
Windows et SQL Server ont commencé à utiliser l'encodage UCS-2 car il était disponible et UTF-16 n'était pas encore finalisé. Heureusement, cependant, les conceptions de UCS-2 et UTF-16 ont été suffisamment conçues pour que les mappages UCS-2 soient un sous-ensemble complet des mappages UTF-16 (ce qui signifie: la plage 0 - 65535 / 0x0000 - 0xFFFF de l'UTF-16 est UCS-2). ET, la plage UTF-16 65536 - 1114111 (0x10000 - 0x10FFFF) est construite à partir de deux points de code dans la plage UCS-2 (plages 0xD800 - 0xDBFF et 0xDC00 - 0xDFFF, en particulier) qui ont été réservés à cet effet et qui n'ont autrement aucune sens. Cette combinaison de deux points de code est connue sous le nom de paire de substitution, et les paires de substitution représentent des caractères au-delà de la plage UCS-2, appelés caractères supplémentaires.
Toutes ces informations expliquent deux aspects des NVARCHAR
données / Unicode dans SQL Server:
- Plusieurs fonctions intégrées (non seulement
NCHAR()
) ne gèrent pas / paires Surrogate caractères supplémentaires lorsqu'ils ne sont pas en utilisant un caractère supplémentaire-Aware Collation (SCA, à savoir un avec _SC
, ou _140_
non _BIN*
dans le nom) parce que le (non-SCA en particulier la collation par défaut SQL_
Les classements) ont été mis en œuvre à l'origine avant l'achèvement de l'UTF-16 (quelque part en 2000, je crois). Les non- SQL_
classements qui ont _90_
ou _100_
en leur nom mais ne _SC
prennent pas en charge les caractères supplémentaires en termes de comparaison et de tri.
- Le jeu de caractères Unicode / UTF-16 complet peut être stocké, sans aucune perte de données, dans les types de données
NVARCHAR
/ NCHAR
/ XML
/ NTEXT
car UCS-2 et UTF-16 sont exactement les mêmes séquences d'octets. La seule différence est que UTF-16 utilise les points de code de substitution pour construire des paires de substitution, et UCS-2 ne peut tout simplement pas les mapper à des caractères, ils apparaissent donc dans les fonctions intégrées comme deux caractères inconnus.
Avec ces informations de fond à l'esprit, nous pouvons maintenant passer par les questions spécifiques:
Je voudrais SELECT NCHAR(128512);
retourner le même que celui-ci:SELECT N'😀';
Cela ne peut se produire que si la base de données actuelle - où la requête est exécutée - a un classement par défaut qui est compatible avec les caractères supplémentaires, et ceux qui ont été introduits dans SQL Server 2012. Les fonctions intégrées qui ont des paramètres d'entrée de chaîne peuvent avoir le classement fourni en ligne via la COLLATE
clause (c'est-à-dire LEN(N'string' COLLATE Some_Collation_SC)
) et n'ont pas besoin d'être exécutés dans une base de données qui a un classement SCA par défaut. Cependant, les fonctions intégrées telles que l' NCHAR()
acceptation d'un INT
paramètre d'entrée et la COLLATE
clause ne sont pas valides dans ce contexte (c'est pourquoi NCHAR()
ne prend en charge les caractères supplémentaires que lorsque la base de données actuelle a un classement par défaut qui est compatible avec les caractères supplémentaires; mais ceci n'est pas nécessaire inconvénients qui peuvent être modifiés, veuillez donc voter pour ma suggestion:La fonction NCHAR () doit toujours renvoyer un caractère supplémentaire pour les valeurs 0x10000 - 0x10FFFF, indépendamment du classement par défaut de la base de données active ).
Y a-t-il une explication pour laquelle, indépendamment du classement, SQL Server peut comprendre et gérer les caractères étendus, sauf du point de vue de NCHAR
?
La façon dont SQL Server peut stocker et récupérer des caractères supplémentaires sans perte de données a été expliquée dans la partie supérieure de cette réponse. Mais, il n'est pas vrai que NCHAR
c'est la seule fonction intégrée qui a des problèmes avec les caractères supplémentaires (lorsque vous n'utilisez pas un classement SCA). Par exemple, LEN(N'😀' COLLATE SQL_Latin1_General_CP1_CI_AS)
renvoie une valeur de 2 tandis que LEN(N'😀' COLLATE Latin1_General_100_CI_AS_SC)
renvoie une valeur de 1.
Si vous accédez au deuxième lien publié dans la question (c'est-à-dire «Informations de classement des caractères supplémentaires de Microsoft») et faites défiler un peu vers le bas, vous verrez un graphique des fonctions intégrées et comment elles se comportent en fonction du classement effectif.
Comment trouver un classement qui a le drapeau "caractère supplémentaire"?
Dans une version de SQL Server antérieure à 2012, vous ne pouvez pas. Mais, à partir de SQL Server 2012, vous pouvez utiliser la requête suivante:
SELECT col.*
FROM sys.fn_helpcollations() col
WHERE col.[name] LIKE N'%[_]SC'
OR col.[name] LIKE N'%[_]SC[_]%'
OR (COLLATIONPROPERTY(col.[name], 'Version') = 3
AND col.[name] NOT LIKE N'%[_]BIN%');
Votre requête était fermée, mais le modèle a commencé par SQL
et les classements SQL Server (c'est-à-dire ceux commençant par SQL_
) sont obsolètes depuis un certain temps en faveur des classements Windows (ceux qui ne commencent pas par SQL_
). Ainsi, les SQL_
classements ne sont pas mis à jour et n'ont donc pas de versions plus récentes qui incluraient l' _SC
option (et à partir de SQL Server 2017, tous les nouveaux classements prennent automatiquement en charge les caractères supplémentaires et n'ont pas besoin, ou n'ont pas, l' _SC
indicateur; et oui, la requête montré juste au-dessus explique cela et reprend les _UTF8
classements ajoutés dans SQL Server 2019).
Pouvez-vous installer des classements sur des instances plus anciennes?
Non, vous ne pouvez pas installer Collations dans une version précédente de SQL Server.
Comment puis-je définir une variable de chaîne Unicode (par exemple nvarchar) sur un caractère supplémentaire en utilisant du code (sans utiliser le caractère supplémentaire réel) dans une base de données où le classement "ne contient pas l'indicateur de caractère supplémentaire (SC)"?
...
Bien que le serveur soit SQL Server 2008 R2, je suis également curieux de savoir quelles solutions pour les versions ultérieures.
Lorsque vous n'utilisez pas de classement SCA, vous pouvez injecter des points de code au-dessus de 65535 / U + FFFF de deux manières:
- Spécifiez la paire de substitution en termes de deux appels à la
NCHAR()
fonction, chacun avec une partie de la paire
- Spécifiez la paire de substitution en termes de conversion de la
VARBINARY
forme de la séquence d'octets Little Endian (c'est-à-dire inversée).
Ces deux méthodes d'insertion de caractères supplémentaires / paires de substitution fonctionneront même si le classement effectif est compatible avec les caractères supplémentaires, et devraient fonctionner de la même manière sur toutes les versions de SQL Server, au moins aussi tôt qu'en 2005 (mais cela fonctionnerait probablement aussi dans SQL Server 2000 également).
Exemple:
- Personnage:
💩
- Nom: Pile of Poo
- Décimal: 128169
- Point de code: U + 1F4A9
- Paire de substitution: U + D83D & U + DF21
SELECT N'💩', -- 💩
UNICODE(N'💩' COLLATE Latin1_General_100_CI_AS), -- 55357
UNICODE(N'💩' COLLATE Latin1_General_100_CI_AS_SC), -- 128169
NCHAR(128169), -- 💩 in DB with _SC Collation, else NULL
NCHAR(0x1F4A9), -- 💩 in DB with _SC Collation, else NULL
CONVERT(VARBINARY(4), 128169), -- 0x0001F4A9
CONVERT(VARBINARY(4), N'💩'), -- 0x3DD8A9DC
CONVERT(NVARCHAR(10), 0x3DD8A9DC), -- 💩 (regardless of DB Collation)
NCHAR(0xD83D) + NCHAR(0xDCA9) -- 💩 (regardless of DB Collation)
MISE À JOUR
Vous pouvez utiliser l'iTVF suivant pour obtenir les valeurs de la paire de substitution (dans les deux INT
et BINARY
sous forme) à partir de n'importe quel point de code entre 65536 - 1114111 (0x010000 - 0x10FFFF). Et, tandis que le paramètre d'entrée est de type INT
, vous pouvez passer sous la forme binaire / hexadécimale du point de code et il sera implicitement converti en la valeur entière correcte.
CREATE FUNCTION dbo.GetSupplementaryCharacterInfo(@CodePoint INT)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN
WITH calc AS
(
SELECT 55232 + (@CodePoint / 1024) AS [HighSurrogateINT],
56320 + (@CodePoint % 1024) AS [LowSurrogateINT]
WHERE @CodePoint BETWEEN 65536 AND 1114111
)
SELECT @CodePoint AS [CodePointINT],
HighSurrogateINT,
LowSurrogateINT,
CONVERT(VARBINARY(3), @CodePoint) AS [CodePointBIN],
CONVERT(BINARY(2), HighSurrogateINT) AS [HighSurrogateBIN],
CONVERT(BINARY(2), LowSurrogateINT) AS [LowSurrogateBIN],
CONVERT(binary(4), NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT)) AS [UTF-16LE],
NCHAR(HighSurrogateINT) + NCHAR(LowSurrogateINT) AS [Character]
FROM calc;
GO
En utilisant la fonction ci-dessus, les deux requêtes suivantes:
SELECT * FROM dbo.GetSupplementaryCharacterInfo(128169);
SELECT * FROM dbo.GetSupplementaryCharacterInfo(0x01F4A9);
les deux renvoient les éléments suivants:
CodePoint HighSurrogate LowSurrgate CodePoint HighSurrgate LowSurrgate UTF-16LE Char
INT INT INT BIN BIN BIN actr
128169 55357 56489 0x01F4A9 0xD83D 0xDCA9 0x3DD8A9DC 💩
MISE À JOUR 2: Une mise à jour encore meilleure!
J'ai adapté l'iTVF illustré ci-dessus pour renvoyer maintenant 188 657 points de code, vous n'avez donc pas besoin de l'adapter à une valeur particulière. Bien sûr, étant un TVF, vous pouvez ajouter une WHERE
clause pour filtrer sur un point de code particulier, ou une plage de points de code, ou "caractères similaires", etc. Et, il comprend des colonnes supplémentaires avec des séquences d'échappement pré-formatées pour construire chaque code point (à la fois BMP et caractères supplémentaires) en T-SQL, HTML et style C (c'est-à-dire \xHHHH
). Lisez tout a propos de ça ici:
Astuce SSMS # 3: Accédez / recherchez facilement TOUS les caractères Unicode (Oui, y compris les Emojis 😸)