web-dev-qa-db-ja.com

SQL ServerのUnicode / NVARCHAR文字列を絵文字または補足文字に設定するにはどうすればよいですか?

Unicode文字列変数を、Unicodeコードポイントに基づいて特定の文字に設定したい。

65535を超えるコードポイントを使用したいのですが、SQL Server 2008 R2データベースの照合順序はSQL_Latin1_General_CP1_CI_ASです。

MicrosoftのNCHARドキュメント によると、NCHAR関数は次のように整数を取ります。

integer_expression

データベースの照合に補助文字(SC)フラグが含まれていない場合、これは0〜65535(0〜0xFFFF)の正の整数です。この範囲外の値が指定された場合、NULLが返されます。補助文字の詳細については、照合およびUnicodeサポートを参照してください。

データベースの照合が補助文字(SC)フラグをサポートしている場合、これは0〜1114111(0〜0x10FFFF)の正の整数です。この範囲外の値が指定された場合、NULLが返されます。

したがって、このコード:

SELECT NCHAR(128512);

このデータベースでNULLを返します。

私はこれと同じように返すことを望みます:

SELECT N'????';

照合順序に「補助文字(SC)フラグが含まれていない」データベースで、コードを使用して(実際の絵文字を使用せずに)Unicode文字列変数(nvarcharなど)を絵文字に設定するにはどうすればよいですか?

絵文字Unicodeコードポイントの完全なリスト

(最終的にはどのキャラクターでも機能させたい。参照しやすいように絵文字を選んだだけだ。)

(サーバーはSQL Server 2008 R2ですが、それ以降のバージョンの解決策にも興味があります。)

方法がないと仮定して、適切な照合があった別のデータベースのインラインユーザー定義関数を参照できますか?

「補足文字」フラグのある照合順序を見つけるにはどうすればよいですか?

これはサーバーにレコードを返しません:

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

SQL Server 2012で動作するLatin1_General_100_CI_AS_SCが導入されたようです。古いインスタンスに照合順序をインストールできますか?

照合参照:

照合に関係なく、SQL ServerがNCHARの観点以外で拡張文字を理解して処理できる理由についての説明はありますか?

25
Riley Major

UCS-2エンコードは常に文字あたり2バイトで、範囲は0〜65535(0x0000-0xFFFF)です。 UTF-16(ビッグエンディアンまたはリトルエンディアンに関係なく)の範囲は0〜1114111(0x0000〜0x10FFFF)です。 UTF-16の0-65535/0x0000-0xFFFFの範囲は1文字あたり2バイトですが、65536/0xFFFFを超える範囲は1文字あたり4バイトです。

WindowsおよびSQL Serverは、UCS-2エンコーディングが使用可能であり、UTF-16がまだ確定されていないため、最初はそれを使用していました。ただし、幸運なことに、UCS-2およびUTF-16の設計には十分な先見性があり、UCS-2マッピングはUTF-16マッピングの完全なサブセットです(つまり、0-65535/0x0000-0xFFFFの範囲)。 UTF-16のis UCS-2)。さらに、UTF-16の65536-1114111(0x10000-0x10FFFF)の範囲は、この目的のために予約されていて、それ以外にはない意味。この2つのコードポイントの組み合わせはサロゲートペアと呼ばれ、サロゲートペアはUCS-2の範囲を超える文字を表し、補助文字と呼ばれます。

これらすべての情報は、SQL ServerのNVARCHAR/Unicodeデータの2つの側面を説明しています。

  1. いくつかの組み込み関数(NCHAR()だけでなく)は、補助文字対応照合(SCA、つまり_SCまたは_140_を備えた照合を使用しない場合、サロゲートペア/補助文字を処理しませんただし、名前に_BIN*は含まれません)。非SCA照合(特にSQL_照合)は、UTF-16が完了する前に最初に実装されたためです(2000年のいつかと思います)。名前にSQL_または_90_を含むが_100_を含まない非_SC照合順序は、比較と並べ替えの点で補助文字を最小限にサポートします。
  2. UCSのため、完全なUnicode/UTF-16文字セットは、データを失うことなく、NVARCHAR/NCHAR/XML/NTEXTデータ型に格納できます。 -2とUTF-16はまったく同じバイトシーケンスです。唯一の違いは、UTF-16がサロゲートペアを構築するためにサロゲートコードポイントを使用し、UCS-2はそれらを任意の文字にマップできないため、組み込み関数では2つの不明な文字として表示されることです。

その背景情報を念頭に置いて、具体的な質問に進むことができます。

SELECT NCHAR(128512);がこれと同じを返すようにしたい:SELECT N'????';

これは、クエリが実行されている現在のデータベースに、補助文字対応の既定の照合順序があり、SQL Server 2012で導入された場合にのみ発生します。文字列入力パラメーターを持つ組み込み関数は、照合順序を指定できますCOLLATE句(つまりLEN(N'string' COLLATE Some_Collation_SC))を介してインライン化し、SCAのデフォルトの照合順序を持つデータベース内で実行する必要はありませんneed。ただし、NCHAR()などの組み込み関数はINT入力パラメーターを受け入れ、COLLATE句はそのコンテキストでは無効です(そのため、NCHAR()は、現在のデータベースにデフォルトの照合が補足文字対応である場合にのみ補足文字をサポートしますが、これは変更できる不必要な不便なので、私の提案に投票してください: NCHAR()関数は常に返す必要がありますアクティブなデータベースのデフォルトの照合に関係なく、値0x10000-0x10FFFFの補足文字 )。

照合に関係なく、SQL ServerがNCHARの観点以外で拡張文字を理解して処理できる理由についての説明はありますか?

SQL Serverがデータ損失なしに補足文字を格納および取得する方法については、この回答の上部で説明しました。ただし、NCHARが(SCA照合順序を使用しない場合に)補足文字に問題がある唯一の組み込み関数であるとは限りません。たとえば、LEN(N'????' COLLATE SQL_Latin1_General_CP1_CI_AS)は2の値を返し、LEN(N'????' COLLATE Latin1_General_100_CI_AS_SC)は1の値を返します。

質問に掲載されている2番目のリンク(「Microsoftの補足文字の照合順序情報」など)に移動して少し下にスクロールすると、組み込み関数のチャートと、有効な照合順序に基づいてそれらがどのように動作するかが表示されます。

「補足文字」フラグのある照合順序を見つけるにはどうすればよいですか?

2012より前のバージョンのSQL Serverではできません。ただし、SQL Server 2012以降では、次のクエリを使用できます。

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%');

クエリは近かったですが、パターンはSQLで始まり、SQL Server照合順序(つまり、SQL_で始まるもの)は、Windows照合順序(SQL_で始まっていないもの)のために廃止されました。したがって、SQL_照合順序は更新されないため、_SCオプションを含む新しいバージョンはありません(SQL Server 2017以降、 すべての新しい照合順序は、補助文字 を自動的にサポートし、必要ありません。または、_SCフラグがあり、はい、すぐ上に表示されているクエリは、SQL Server 2019で追加された_UTF8照合を選択するだけでなく、それを考慮しています。

古いインスタンスに照合順序をインストールできますか?

いいえ、以前のバージョンのSQL Serverに照合順序をインストールすることはできません。

照合順序に「補助文字(SC)フラグが含まれていない」データベースで、コードを使用して(実際の補助文字を使用せずに)Unicode文字列変数(nvarcharなど)を補助文字に設定するにはどうすればよいですか?
...
サーバーはSQL Server 2008 R2ですが、それ以降のバージョンの解決策にも興味があります。

SCA照合を使用しない場合、次の2つの方法で65535/U + FFFFを超えるコードポイントを挿入できます。

  1. NCHAR()関数の2つの呼び出しでサロゲートペアを指定します。
  2. リトルエンディアン(つまり反転)バイトシーケンスのVARBINARY形式を変換するという観点からサロゲートペアを指定します。

補助文字/サロゲートペアを挿入するこれらの2つの方法は、有効な照合順序が補助文字に対応している場合でも機能し、少なくとも2005年までのSQL Serverのすべてのバージョンでまったく同じように機能するはずです(ただし、おそらくSQL Server 2000も)。

例:

  • 文字:

    ????

  • 名前:Poo of Poo
  • 10進数:128169
  • コードポイント:U + 1F4A9
  • サロゲートペア: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)

[〜#〜]更新[〜#〜]

次のiTVFを使用して、65536-1114111(0x010000-0x10FFFF)のコードポイントからサロゲートペアの値(INTBINARYの両方の形式)を取得できます。また、入力パラメーターのタイプはINTですが、コードポイントのバイナリ/ 16進数形式で渡すことができ、暗黙的に正しい整数値に変換されます。

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

上記の関数を使用して、次の2つのクエリ:

SELECT * FROM dbo.GetSupplementaryCharacterInfo(128169);

SELECT * FROM dbo.GetSupplementaryCharacterInfo(0x01F4A9);

どちらも次を返します:

CodePoint  HighSurrogate  LowSurrgate  CodePoint  HighSurrgate  LowSurrgate  UTF-16LE   Char
INT        INT            INT          BIN        BIN           BIN                     actr
128169     55357          56489        0x01F4A9   0xD83D        0xDCA9       0x3DD8A9DC   ????

更新2:より良い更新!

上記のiTVFを適合させて、188,657コードポイントを返すようにしたので、特定の値に合わせる必要はありません。もちろん、TVFの場合、WHERE句を追加して、特定のコードポイント、コードポイントの範囲、または「類似文字」などでフィルタリングできます。また、事前フォーマット済みの追加の列が含まれていますT-SQLで各コードポイント(BMPと補足文字の両方))を構築するエスケープシーケンス(「_SC」または「_140_」照合を必要としない)、HTML(およびXML)、一般的なスタイル多くのアプリ言語( "\ uHHHH"; C++/C#/ F#/ Java/JavaScript/Julia /など)に使用されます)、そして最後に、すべてのコードポイントを処理する少し新しい他の一般的なスタイルBMP( "\ UHHHHHHHH"; C/C++/C#/ F#/ Julia /などに使用されます)だけではありません。

それについてここですべて読んでください:

SSMSヒント#3:すべてのUnicode文字に簡単にアクセス/検索(はい、絵文字を含みます????)

40
Solomon Rutzky