Je veux définir une variable de chaîne Unicode sur un caractère particulier en fonction de son point de code Unicode.
Je souhaite utiliser un point de code au-delà de 65535, mais la base de données SQL Server 2008 R2 a un classement de SQL_Latin1_General_CP1_CI_AS
.
Selon documentation NCHAR de Microsoft , la fonction NCHAR
prend un entier comme suit:
expression_entier
Lorsque le classement de la base de données ne contient pas l'indicateur de caractère supplémentaire (SC), il s'agit d'un nombre entier positif compris entre 0 et 65535 (0 et 0xFFFF). Si une valeur en dehors de cette plage est spécifiée, NULL est retourné. Pour plus d'informations sur les caractères supplémentaires, voir Prise en charge du classement et d'Unicode.
Lorsque le classement de la base de données prend en charge l'indicateur de caractère supplémentaire (SC), il s'agit d'un nombre entier positif compris entre 0 et 1114111 (0 et 0x10FFFF). Si une valeur en dehors de cette plage est spécifiée, NULL est retourné.
Donc, ce code:
SELECT NCHAR(128512);
Renvoie NULL
dans cette base de données.
Je voudrais qu'il renvoie le même que celui-ci:
SELECT N'????';
Comment puis-je définir une variable de chaîne Unicode (par exemple nvarchar) sur un emoji en utilisant du code (sans utiliser le caractère emoji réel) dans une base de données où le classement "ne contient pas l'indicateur de caractère supplémentaire (SC)"?
Liste complète des points de code emoji Unicode
(En fin de compte, je veux que n'importe quel personnage fonctionne. J'ai simplement choisi les emoji pour faciliter la référence.)
(Bien que le serveur soit SQL Server 2008 R2, je suis également curieux de savoir quelles solutions pour les versions ultérieures.)
En supposant qu'il n'y ait aucun moyen, pourrais-je référencer une fonction définie par l'utilisateur en ligne dans une autre base de données qui avait un classement approprié?
Comment trouver un classement qui a le drapeau "caractère supplémentaire"?
Cela ne renvoie aucun enregistrement sur notre serveur:
SELECT * FROM sys.fn_helpcollations()
WHERE name LIKE 'SQL%[_]SC';
Il semble que SQL Server 2012 a introduit Latin1_General_100_CI_AS_SC
qui fonctionnerait. Pouvez-vous installer des classements sur des instances plus anciennes?
Références de collation:
Y a-t-il une explication pour laquelle, indépendamment du classement, SQL Server peut comprendre et traiter les caractères étendus, sauf du point de vue de NCHAR
?
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 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 données NVARCHAR
/Unicode dans SQL Server:
NCHAR()
) ne gèrent pas les paires de substitution/caractères supplémentaires lorsque vous n'utilisez pas un classement supplémentaire conscient des caractères (SCA; c'est-à-dire un avec _SC
, ou_140_
mais pas _BIN*
dans le nom) car les classements non SCA (en particulier les classements SQL_
) ont été initialement implémentés avant UTF-16 en cours d'achèvement (en 2000, je crois). Les classements autres que SQL_
Qui ont _90_
Ou _100_
Dans leur nom mais pas _SC
Ont une prise en charge minimale des caractères supplémentaires en termes de comparaison et de tri.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 que
SELECT NCHAR(128512);
renvoie la même chose que ceci: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 clause COLLATE
(c'est-à-dire LEN(N'string' COLLATE Some_Collation_SC)
) et ne pas besoin être exécuté dans une base de données qui a un classement SCA par défaut. Cependant, les fonctions intégrées telles que NCHAR()
acceptent un paramètre d'entrée INT
et la clause COLLATE
n'est pas valide 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 c'est un inconvénient inutile qui peut être modifié, veuillez donc voter pour ma suggestion: la fonction NCHAR () devrait toujours renvoyer 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 traiter 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 section supérieure de cette réponse. Mais, il n'est pas vrai que NCHAR
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 classements SQL_
Ne sont pas mis à jour et n'ont donc pas de versions plus récentes qui incluraient l'option _SC
(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'indicateur _SC
; et oui, la requête affichée immédiatement ci-dessus en tient compte et récupère les classements _UTF8
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 connaître les 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:
NCHAR()
, chacun avec une partie de la paireVARBINARY
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:
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 (sous la forme INT
et BINARY
) à 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 clause WHERE
pour filtrer sur un point de code particulier, ou une plage de points de code, ou des "caractères similaires", etc. Et, il comprend des colonnes supplémentaires avec des formats pré-formatés séquences d'échappement pour construire chaque point de code (à la fois BMP et caractères supplémentaires) dans T-SQL (sans nécessiter un classement "_SC
" ou "_140_
") , HTML (et XML), le style commun à de nombreux langages d'application ("\ uHHHH"; utilisé pour C++/C #/F #/Java/JavaScript/Julia/etc), et enfin légèrement plus récent, un autre style commun qui gère tous les points de code, pas seulement BMP ("\ UHHHHHHHH"; utilisé pour C/C++/C #/F #/Julia/etc).
Lisez tout a propos de ça ici: