Domyślnym zestawieniem mojego serwera jest Latin1_General_CI_AS, zgodnie z tym zapytaniem:
SELECT SERVERPROPERTY('Collation') AS Collation;
Byłem zaskoczony, gdy odkryłem, że dzięki temu zestawieniu mogę dopasowywać znaki nie będące cyframi w ciągach znaków, używając predykatu LIKE '[0-9]'
.
Dlaczego w domyślnym zestawieniu tak się dzieje? Nie mogę wymyślić przypadku, w którym byłoby to przydatne. Wiem, że mogę obejść to zachowanie za pomocą sortowania binarnego, ale wydaje się to dziwnym sposobem na wdrożenie domyślnego sortowania.
Filtrowanie cyfr powoduje powstanie znaków innych niż cyfry
Mogę zademonstrować to zachowanie, tworząc kolumnę zawierającą wszystkie możliwe jednobajtowe wartości znaków i filtrując wartości za pomocą predykatu dopasowującego cyfry.
Poniższa instrukcja tworzy tymczasową tabelę z 256 wierszami, po jednym dla każdego punktu kodowego na bieżącej stronie kodowej:
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;
Każdy wiersz zawiera wartość całkowitą punktu kodowego oraz wartość znakową punktu kodowego. Nie wszystkie wartości znaków są wyświetlane - niektóre punkty kodowe są znakami ściśle kontrolującymi. Oto wybiórcza próbka wyników 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 ÿ
Oczekiwałbym, że będę mógł filtrować kolumnę Symbol, aby znaleźć cyfry przy użyciu predykatu LIKE i określając zakres znaków od „0” do „9”:
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';
Daje zaskakującą wydajność:
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 ¾
Zestaw punktów kodowych od 48 do 57 to te, których oczekuję. Zaskakuje mnie to, że symbole dla indeksu górnego i ułamków są również zawarte w zestawie wyników!
Może istnieć matematyczny powód, by wykładniki i ułamki traktować jak liczby, ale nazywanie ich cyframi wydaje się niewłaściwe.
Korzystanie z sortowania binarnego jako obejścia
Rozumiem, że aby uzyskać oczekiwany wynik, mogę wymusić odpowiednie sortowanie binarne Latin1_General_BIN:
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;
Zestaw wyników zawiera tylko punkty kodowe 48 do 57:
CodePoint Symbol
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9