私のサーバーのデフォルトの照合は、次のクエリによって決定されるLatin1_General_CI_ASです。
SELECT SERVERPROPERTY('Collation') AS Collation;
この照合により、述語を使用して文字列内の数字以外の文字と一致できることを発見して驚きましたLIKE '[0-9]'
。
デフォルトの照合でこれが起こるのはなぜですか?これが役立つケースは考えられません。バイナリ照合を使用して動作を回避できることはわかっていますが、デフォルトの照合を実装する奇妙な方法のようです。
数字をフィルタリングすると、数字以外の文字が生成されます
すべての可能なシングルバイト文字値を含む列を作成し、数字一致述語で値をフィルタリングすることにより、動作を実証できます。
次のステートメントは、現在のコードページの各コードポイントに1つずつ、256行の一時テーブルを作成します。
WITH P0(_) AS (SELECT 0 UNION ALL SELECT 0),
P1(_) AS (SELECT 0 FROM P0 AS L CROSS JOIN P0 AS R),
P2(_) AS (SELECT 0 FROM P1 AS L CROSS JOIN P1 AS R),
P3(_) AS (SELECT 0 FROM P2 AS L CROSS JOIN P2 AS R),
Tally(Number) AS (
SELECT -1 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM P3
)
SELECT Number AS CodePoint, CHAR(Number) AS Symbol
INTO #CodePage
FROM Tally
WHERE Number >= 0 AND Number <= 255;
各行には、コードポイントの整数値とコードポイントの文字値が含まれています。すべての文字値が表示可能というわけではありません-一部のコードポイントは厳密に制御文字です。次に、出力の選択サンプルを示しますSELECT CodePoint, Symbol FROM #CodePage
。
0
1
2
...
32
33 !
34 "
35 #
...
48 0
49 1
50 2
...
65 A
66 B
67 C
...
253 ý
254 þ
255 ÿ
LIKE述語を使用し、「0」から「9」までの文字の範囲を指定して、Symbol列でフィルタリングして数字を見つけることができると期待しています。
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';
それは驚くべき出力を生成します:
CodePoint Symbol
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9
178 ²
179 ³
185 ¹
188 ¼
189 ½
190 ¾
48から57までのコードポイントのセットは、私が期待するものです。私が驚いたのは、上付き文字と分数の記号も結果セットに含まれていることです!
指数と分数を数字と考える数学的理由があるかもしれませんが、それらを数字と呼ぶのは間違っているようです。
回避策としてバイナリ照合を使用する
期待どおりの結果を得るために、対応するバイナリ照合Latin1_General_BINを強制できることを理解しています。
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;
結果セットには、48〜57のコードポイントのみが含まれます。
CodePoint Symbol
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9