Die UCS-2-Codierung besteht immer aus 2 Bytes pro Zeichen und hat einen Bereich von 0 bis 65535 (0x0000 bis 0xFFFF). UTF-16 (unabhängig von Big Endian oder Little Endian) hat einen Bereich von 0 - 1114111 (0x0000 - 0x10FFFF). Der Bereich 0 - 65535 / 0x0000 - 0xFFFF von UTF-16 beträgt 2 Byte pro Zeichen, während der Bereich über 65536 / 0xFFFF 4 Byte pro Zeichen beträgt.
Windows und SQL Server verwendeten zunächst die UCS-2-Codierung, da diese verfügbar war und UTF-16 noch nicht finalisiert wurde. Glücklicherweise gab es in den Entwürfen von UCS-2 und UTF-16 genügend Voraussicht, dass die UCS-2-Zuordnungen eine vollständige Teilmenge der UTF-16-Zuordnungen darstellen (dh der Bereich 0 - 65535 / 0x0000 - 0xFFFF) von UTF-16 ist UCS-2). AND, der Bereich 65536 - 1114111 (0x10000 - 0x10FFFF) von UTF-16 wird aus zwei Codepunkten im UCS-2-Bereich (Bereiche 0xD800 - 0xDBFF und 0xDC00 - 0xDFFF, speziell) erstellt, die für diesen Zweck reserviert wurden und ansonsten keine haben Bedeutung. Diese Kombination von zwei Codepunkten wird als Ersatzpaar bezeichnet, und Ersatzpaare stehen für Zeichen außerhalb des UCS-2-Bereichs, die als Zusatzzeichen bezeichnet werden.
All diese Informationen erläutern zwei Aspekte von NVARCHAR
/ Unicode-Daten in SQL Server:
- Mehrere Funktionen in gebaut (nicht nur
NCHAR()
) nicht Surrogate Pairs / Ergänzende Zeichen behandeln , wenn kein zusätzlichen Charakter-Aware Sortierungs mit (SCA, dh einer mit _SC
, oder _140_
aber nicht _BIN*
im Namen) , weil das Nicht-SCA Sortierungen (vor allem der SQL_
Kollatierungen) wurden ursprünglich implementiert, bevor UTF-16 abgeschlossen wurde (irgendwann im Jahr 2000, glaube ich). Die Nicht- SQL_
Kollatierungen, die _90_
oder _100_
in ihren Namen enthalten sind, jedoch keine _SC
minimale Unterstützung für Zusatzzeichen in Bezug auf Vergleich und Sortierung aufweisen.
- Der vollständige Unicode / UTF-16 - Zeichensatz gespeichert werden, ohne Datenverlust in den
NVARCHAR
/ NCHAR
/ XML
/ NTEXT
Datentypen , weil UCS-2 und UTF-16 exakt die gleichen Byte - Sequenzen sind. Der einzige Unterschied besteht darin, dass UTF-16 die Ersatzcodepunkte verwendet, um Ersatzpaare zu erstellen, und UCS-2 kann sie einfach keinen Zeichen zuordnen. Daher werden sie den integrierten Funktionen als zwei unbekannte Zeichen angezeigt.
Vor diesem Hintergrund können wir nun die spezifischen Fragen durchgehen:
Ich möchte SELECT NCHAR(128512);
das Gleiche wie das zurückgeben:SELECT N'😀';
Dies kann nur passieren, wenn die aktuelle Datenbank, in der die Abfrage ausgeführt wird, eine Standardkollation hat, die Supplementary Character-Aware ist und die in SQL Server 2012 eingeführt wurde. Für integrierte Funktionen mit Zeichenfolge-Eingabeparametern kann die Kollation bereitgestellt werden inline über die COLLATE
Klausel (dh LEN(N'string' COLLATE Some_Collation_SC)
) und nicht müssen innerhalb einer Datenbank ausgeführt werden , die eine SCA Standardkollatierung hat. Integrierte Funktionen wie das NCHAR()
Akzeptieren eines INT
Eingabeparameters und die COLLATE
Klausel sind in diesem Kontext jedoch nicht gültig (weshalb NCHAR()
nur Zusatzzeichen unterstützt werden, wenn in der aktuellen Datenbank eine Standardkollatierung vorhanden ist, die Supplementary Character-Aware ist. Dies ist jedoch nicht erforderlich Unannehmlichkeiten, die geändert werden können, also stimmen Sie für meinen Vorschlag ab:Die Funktion NCHAR () sollte unabhängig von der Standardkollatierung der aktiven Datenbank immer ein Ergänzungszeichen für die Werte 0x10000 - 0x10FFFF zurückgeben .
Gibt es eine Erklärung dafür, warum SQL Server unabhängig von der Sortierung die erweiterten Zeichen verstehen und damit umgehen kann, außer aus der Perspektive von NCHAR
?
Wie SQL Server zusätzliche Zeichen ohne Datenverlust speichern und abrufen kann, wurde im oberen Abschnitt dieser Antwort erläutert. Es ist jedoch nicht wahr, dass dies NCHAR
die einzige integrierte Funktion ist, bei der Probleme mit zusätzlichen Zeichen auftreten (wenn keine SCA-Kollatierung verwendet wird). Gibt beispielsweise den LEN(N'😀' COLLATE SQL_Latin1_General_CP1_CI_AS)
Wert 2 und den LEN(N'😀' COLLATE Latin1_General_100_CI_AS_SC)
Wert 1 zurück.
Wenn Sie zu dem in der Frage angegebenen zweiten Link gehen (z. B. "Microsoft's Supplementary Characters Collation Information") und ein wenig nach unten scrollen, sehen Sie ein Diagramm der integrierten Funktionen und wie sie sich basierend auf der effektiven Kollatierung verhalten.
Wie finde ich eine Kollatierung mit dem Zusatzzeichen?
In einer Version von SQL Server vor 2012 ist dies nicht möglich. Ab SQL Server 2012 können Sie jedoch die folgende Abfrage verwenden:
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%');
Ihre Abfrage war in der Nähe, aber das Muster, mit dem begonnen wurde, SQL
und die SQL Server-Kollatierungen (dh die Kollatierungen, die mit beginnen SQL_
) wurden für eine Weile zugunsten der Windows-Kollatierungen (die nicht mit beginnen SQL_
) verworfen . Daher werden die SQL_
Kollatierungen nicht aktualisiert und haben daher keine neueren Versionen, die diese _SC
Option enthalten würden (und ab SQL Server 2017 unterstützen alle neuen Kollatierungen automatisch zusätzliche Zeichen und benötigen oder haben nicht das _SC
Flag und ja, die Abfrage Die direkt darüber angezeigten Konten berücksichtigen dies und _UTF8
greifen die in SQL Server 2019 hinzugefügten Kollatierungen auf.
Können Sie Kollatierungen auf älteren Instanzen installieren?
Nein, Sie können Collations nicht in einer früheren Version von SQL Server installieren.
Wie kann ich eine Unicode-Zeichenfolgenvariable (z. B. nvarchar) mithilfe von Code (ohne Verwendung des tatsächlichen Zusatzzeichens) in einer Datenbank auf ein Zusatzzeichen setzen, in der die Kollatierung "das Zusatzzeichen (SC) -Flag nicht enthält"?
...
Obwohl der Server SQL Server 2008 R2 ist, bin ich auch neugierig auf Lösungen für spätere Versionen.
Wenn Sie keine SCA-Kollatierung verwenden, können Sie Codepunkte über 65535 / U + FFFF auf zwei Arten einfügen:
- Geben Sie das Ersatzpaar in Form von zwei Aufrufen an die
NCHAR()
Funktion mit jeweils einem Teil des Paars an
- Geben Sie das Ersatzpaar an, um die
VARBINARY
Form der Little-Endian-Bytefolge (dh der umgekehrten Bytefolge) zu konvertieren .
Diese beiden Methoden zum Einfügen von Ergänzungszeichen / Ersatzpaaren funktionieren auch dann, wenn die effektive Kollatierung sich der ergänzenden Zeichen bewusst ist, und sollten in allen Versionen von SQL Server mindestens bis 2005 gleich funktionieren (obwohl dies wahrscheinlich auch in funktionieren würde Auch SQL Server 2000).
Beispiel:
- Charakter:
💩
- Name: Haufen von Poo
- Dezimalzahl: 128169
- Code Point: U + 1F4A9
- Ersatzpaar : 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)
AKTUALISIEREN
Sie können den folgenden iTVF verwenden, um die Ersatzpaarwerte (in beiden INT
und in BINARY
Form) von einem beliebigen Codepunkt zwischen 65536 - 1114111 (0x010000 - 0x10FFFF) abzurufen. Und während der Eingabeparameter vom Typ ist INT
, können Sie die Binär- / Hexadezimalform des Codepunkts übergeben, und er wird implizit in den richtigen ganzzahligen Wert konvertiert.
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
Mit der obigen Funktion werden die folgenden zwei Abfragen ausgeführt:
SELECT * FROM dbo.GetSupplementaryCharacterInfo(128169);
SELECT * FROM dbo.GetSupplementaryCharacterInfo(0x01F4A9);
beide geben Folgendes zurück:
CodePoint HighSurrogate LowSurrgate CodePoint HighSurrgate LowSurrgate UTF-16LE Char
INT INT INT BIN BIN BIN actr
128169 55357 56489 0x01F4A9 0xD83D 0xDCA9 0x3DD8A9DC 💩
UPDATE 2: Ein noch besseres Update!
Ich habe die oben gezeigte iTVF so angepasst, dass sie jetzt 188.657 Codepunkte zurückgibt, sodass Sie keinen bestimmten Wert anpassen müssen. Als TVF können Sie natürlich eine WHERE
Klausel hinzufügen , um nach einem bestimmten Codepunkt oder einem Bereich von Codepunkten oder "ähnlichen Zeichen" usw. zu filtern. Außerdem enthält sie zusätzliche Spalten mit vorformatierten Escape-Sequenzen, um jeden Code zu erstellen point (sowohl BMP- als auch Zusatzzeichen) in T-SQL, HTML und C-Style (dh \xHHHH
). Lesen Sie hier alles darüber:
SSMS-Tipp 3: Einfacher Zugriff auf ALLE Unicode-Zeichen (Ja, einschließlich Emojis 😸)