Wie setze ich eine SQL Server Unicode / NVARCHAR-Zeichenfolge auf ein Emoji oder ein Zusatzzeichen?

22

Ich möchte eine Unicode-Zeichenfolgenvariable basierend auf ihrem Unicode-Codepunkt auf ein bestimmtes Zeichen festlegen.

Ich möchte einen Codepunkt jenseits von 65535 verwenden, aber die SQL Server 2008 R2-Datenbank hat eine Sortierung von SQL_Latin1_General_CP1_CI_AS.

Gemäß der NCHAR-Dokumentation von Microsoft nimmt die NCHARFunktion eine Ganzzahl wie folgt an:

integer_expression

Wenn die Sortierung der Datenbank nicht das Zusatzzeichen (SC) enthält, ist dies eine positive ganze Zahl von 0 bis 65535 (0 bis 0xFFFF). Wenn ein Wert außerhalb dieses Bereichs angegeben wird, wird NULL zurückgegeben. Weitere Informationen zu zusätzlichen Zeichen finden Sie unter Sortierung und Unicode-Unterstützung.

Wenn die Sortierung der Datenbank das Zusatzzeichen (SC) -Flag unterstützt, ist dies eine positive ganze Zahl von 0 bis 1114111 (0 bis 0x10FFFF). Wenn ein Wert außerhalb dieses Bereichs angegeben wird, wird NULL zurückgegeben.

Also dieser Code:

SELECT NCHAR(128512);

Gibt NULLin dieser Datenbank zurück.

Ich würde es gerne so zurückgeben:

SELECT N'😀';

Wie kann ich eine Unicode-Zeichenfolgenvariable (z. B. nvarchar) mithilfe von Code (ohne Verwendung des eigentlichen Emoji-Zeichens) in einer Datenbank, in der die Kollatierung "kein SC-Flag (Additional Character) enthält", auf ein Emoji setzen?

Vollständige Liste der Emoji-Unicode-Codepunkte

(Letztendlich möchte ich, dass jeder Charakter funktioniert. Ich habe mich für Emoji entschieden, um das Nachschlagen zu erleichtern.)

(Obwohl der Server SQL Server 2008 R2 ist, bin ich auch neugierig auf Lösungen für spätere Versionen.)

Unter der Annahme, dass es keinen Weg gibt, könnte ich auf eine benutzerdefinierte Inline-Funktion in einer anderen Datenbank verweisen, die über eine geeignete Kollatierung verfügt?

Wie finde ich eine Kollatierung mit dem Zusatzzeichen?

Dies gibt keine Datensätze auf unserem Server zurück:

SELECT * FROM sys.fn_helpcollations() 
WHERE name LIKE 'SQL%[_]SC';

Offenbar wurde SQL Server 2012 eingeführt, Latin1_General_100_CI_AS_SCdas funktionieren würde. Können Sie Kollatierungen auf älteren Instanzen installieren?

Kollatierungsreferenzen:

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?

Riley Major
quelle
Vielen Dank für die umfangreichen Zusatzinformationen. Ich bin nicht länger mit diesem Problem konfrontiert, aber ich werde diese Informationen mental als Lesezeichen speichern.
Riley Major
1
Kein Problem. Ich dachte nicht, dass Sie noch etwas brauchen , nur um die Anpassung zu schätzen / nutzen zu können ...
Solomon Rutzky

Antworten:

35

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:

  1. 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 _SCminimale Unterstützung für Zusatzzeichen in Bezug auf Vergleich und Sortierung aufweisen.
  2. Der vollständige Unicode / UTF-16 - Zeichensatz gespeichert werden, ohne Datenverlust in den NVARCHAR/ NCHAR/ XML/ NTEXTDatentypen , 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 COLLATEKlausel (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 INTEingabeparameters und die COLLATEKlausel 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 NCHARdie 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, SQLund 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 _SCOption enthalten würden (und ab SQL Server 2017 unterstützen alle neuen Kollatierungen automatisch zusätzliche Zeichen und benötigen oder haben nicht das _SCFlag und ja, die Abfrage Die direkt darüber angezeigten Konten berücksichtigen dies und _UTF8greifen 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:

  1. Geben Sie das Ersatzpaar in Form von zwei Aufrufen an die NCHAR()Funktion mit jeweils einem Teil des Paars an
  2. Geben Sie das Ersatzpaar an, um die VARBINARYForm 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 INTund in BINARYForm) 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 WHEREKlausel 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 😸)

Solomon Rutzky
quelle
1
Großartige Arbeit, Solomon! Geniale Erklärung
Ronen Ariely