web-dev-qa-db-ja.com

Unicode文字列が空でない場合、MS SQL Serverが空の文字列チェックの結果を返すのはなぜですか

select * from (select N'ግዜ ' as t) as t2 where t= ''

文字列「ግዜ」は上記のチェックと一致しますが、これはなぜですか?

5
Aussie Ash

これらの特定の文字のexact理由はわかりませんが、t 問題は古い照合に関係しています (最後の更新セクションを参照してください)。そして、それらが等しいのは空の文字列だけではなく、それらの文字の1つだけでもあります。

SELECT * FROM (SELECT N'ግዜ') tab(col) WHERE tab.col = N'ግ';

また、大文字と小文字を区別する照合を実行した場合、複数の文字を使用しても、それらは同じになります。

SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግግግግ' COLLATE SQL_Latin1_General_CP1_CS_AS;
SELECT * FROM (SELECT N'ግ') t(c) WHERE t.c = N'ዜዜዜዜ' COLLATE SQL_Latin1_General_CP1_CS_AS;
SELECT * FROM (SELECT N'ዜ') t(c) WHERE t.c = N'ግግግግ' COLLATE SQL_Latin1_General_CP1_CS_AS;

「同等の」Windows照合順序にも同じ問題があります。

SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_CS_AS;
SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_CS_AS_KS_WS;

しかし、Windows Collat​​ionsの新しいバージョン(つまり、100シリーズ以降)は問題を「修正」し、これらはもはや同等ではないようです:

SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_100_CI_AI;
SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_100_CI_AS;

そしてもちろん、バイナリのWindows照合順序(古いシリーズと新しいシリーズの両方)は正常に機能します。これは、次のものが一致を報告しないためです。

SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_BIN;
SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_BIN2;
SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_100_BIN;
SELECT * FROM (SELECT N'ግዜ') t(c) WHERE t.c = N'ግ' COLLATE Latin1_General_100_BIN2;

更新(2015-08-20)
http://www.unicode.org/http://site.icu-project.org/ に関するドキュメントに6時間注いだ後、および他のいくつかのUnicode関連サイトで、2008年の直前に発生した可能性のある「重み付け」の変更の証拠を見つけるのをやめました(SQL Server 2008で新しい100シリーズの照合が導入されました)。しかし、私はここでテストされている2つの文字について www.fileformat.info で次の情報を見つけました。

そこで、次のプロジェクトに移り、SQL Server 2008のMSDNページで 照合とUnicodeのサポート について以下のことを見つけました。

SQL Server 2008では、Windows Server 2008が提供する照合に完全に一致する新しい照合が導入されました。これらの80の新しい照合順序は、* _ 100バージョン参照で示されます。それらは、ユーザーに最新かつ言語的に正確な文化的分類規則を提供します。サポートには以下が含まれます。

  • ...
  • 同等に比較されるはずだった、以前は重み付けされていなかった文字に重み付けが追加されました。

キャラクターのソートウェイトがないということは、キャラクターが事実上見えないということです。

物語の教訓:そんなに頑張らないでください。より早くあきらめる;-)

更新(2018-09-20)

何が起こっているかをより視覚的に示すために、以下のクエリは、各BMP文字(コードポイント0-65535/U + 0000-U + FFFF))を空の文字列と比較します。比較は異なる照合順序を使用して繰り返し:BIN2、SQL Server照合順序、SQL Server 2000で開始したLatin1_General、SQL Server 2008で開始したLatin1_General、SQL Server 2008で開始したJapanese_XJIS、SQL Server 2017で開始したJapanese_XJIS。 SQL Server 2008は、両方が同じ数の一致を返すことを示していますが、新しいJapanese_XJIS照合順序は異なる番号を返します(SQL Server 2017で更新された照合順序は日本語照合順序のみです)これは、並べ替えの重みが不足している文字数を示すために行われますさまざまな照合バージョン間で。

;WITH nums AS
(
  SELECT TOP (65536) (ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1) AS [CodePoint]
  FROM   [master].[sys].[columns] col
  CROSS JOIN [master].[sys].[objects] obj
)
SELECT nums.[CodePoint],
       COALESCE(NCHAR(nums.[CodePoint]), N'TOTALS:') AS [Character],
       COUNT(CASE WHEN (NCHAR(nums.[CodePoint]) = N''
                 COLLATE Latin1_General_BIN2) THEN 1 END) AS [BIN2],
       COUNT(CASE WHEN (NCHAR(nums.[CodePoint]) = N''
                 COLLATE SQL_Latin1_General_CP1_CS_AS) THEN 1 END) AS [SQL Collations],
       COUNT(CASE WHEN (NCHAR(nums.[CodePoint]) = N''
                 COLLATE Latin1_General_CS_AS_KS_WS) THEN 1 END) AS [SQL2000 Latin1],
       COUNT(CASE WHEN (NCHAR(nums.[CodePoint]) = N''
                 COLLATE Latin1_General_100_CS_AS_KS_WS) THEN 1 END) AS [SQL2008 Latin1],
       COUNT(CASE WHEN (NCHAR(nums.[CodePoint]) = N''
                 COLLATE Japanese_XJIS_100_CS_AS_KS_WS) THEN 1 END) AS [SQL2008 Japanese],
       COUNT(CASE WHEN (NCHAR(nums.[CodePoint]) = N''
                 COLLATE Japanese_XJIS_140_CS_AS_KS_WS) THEN 1 END) AS [SQL2017 Japanese]
FROM   nums
GROUP BY ROLLUP ((nums.[CodePoint], NCHAR(nums.[CodePoint])));

すべての行の詳細を表示するには、上記のクエリを実行します。ただし、要約すると、次のようになります。

BIN2  SQL Collations SQL2000 Latin1  SQL2008 Latin1  SQL2008 Japanese  SQL2017 Japanese
1     21230          21229           5840            5840              3375
10
Solomon Rutzky