Susunan standar server saya adalah Latin1_General_CI_AS, sebagaimana ditentukan oleh kueri ini:
SELECT SERVERPROPERTY('Collation') AS Collation;
Saya terkejut menemukan bahwa dengan susunan ini saya dapat mencocokkan karakter non-digit dalam string menggunakan predikat LIKE '[0-9]'
.
Mengapa dalam susunan standar apakah ini terjadi? Saya tidak bisa memikirkan kasus di mana ini akan berguna. Saya tahu saya bisa mengatasi perilaku menggunakan binary collation, tetapi sepertinya cara yang aneh untuk mengimplementasikan collation default.
Memfilter digit menghasilkan karakter non-digit
Saya bisa mendemonstrasikan perilaku dengan membuat kolom yang berisi semua kemungkinan nilai karakter byte tunggal dan memfilter nilai dengan predikat pencocokan digit.
Pernyataan berikut membuat tabel sementara dengan 256 baris, satu untuk setiap titik kode di halaman kode saat ini:
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;
Setiap baris berisi nilai integer dari titik kode, dan nilai karakter dari titik kode. Tidak semua nilai karakter dapat ditampilkan - beberapa titik kode sepenuhnya mengontrol karakter. Berikut adalah contoh selektif dari output 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 ÿ
Saya berharap dapat memfilter pada kolom Simbol untuk menemukan karakter digit menggunakan predikat LIKE dan menentukan rentang karakter '0' hingga '9':
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';
Ini menghasilkan output yang mengejutkan:
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 ¾
Himpunan poin kode 48 hingga 57 adalah yang saya harapkan. Yang mengejutkan saya adalah simbol untuk superskrip dan fraksi juga termasuk dalam set hasil!
Mungkin ada alasan matematis untuk menganggap eksponen dan pecahan sebagai angka, tetapi tampaknya salah menyebut angka.
Menggunakan binary collation sebagai solusinya
Saya mengerti bahwa untuk mendapatkan hasil yang saya harapkan, saya bisa memaksa pemeriksaan biner yang sesuai Latin1_General_BIN:
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;
Set hasil hanya mencakup poin kode 48 hingga 57:
CodePoint Symbol
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9