По умолчанию мой сервер сортировки является 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