我的服务器的默认排序规则是Latin1_General_CI_AS,由以下查询确定:
SELECT SERVERPROPERTY('Collation') AS Collation;
我很惊讶地发现,通过这种归类,我可以使用谓词匹配字符串中的非数字字符LIKE '[0-9]'
。
为什么在默认排序规则中会发生这种情况?我想不出一个有用的例子。我知道我可以使用二进制排序规则来解决此问题,但这似乎是实现默认排序规则的一种奇怪方法。
过滤数字会产生非数字字符
我可以通过创建包含所有可能的单字节字符值的列并使用数字匹配谓词过滤值来演示此行为。
以下语句创建一个临时表,该表具有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 ÿ
我希望能够在Symbol列上进行过滤,以使用LIKE谓词并指定字符'0'到'9'的范围来查找数字字符:
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