การเปรียบเทียบค่าเริ่มต้นของเซิร์ฟเวอร์ของฉันคือ Latin1_General_CI_AS ตามที่กำหนดโดยแบบสอบถามนี้:
SELECT SERVERPROPERTY('Collation') AS Collation;
ฉันรู้สึกประหลาดใจที่ค้นพบว่าด้วยการเปรียบเทียบนี้ฉันสามารถจับคู่อักขระที่ไม่ใช่ตัวเลขในสตริงโดยใช้เพLIKE '[0-9]'
รดิเคต
ทำไมในการจัดเรียงเริ่มต้นนี้เกิดขึ้นได้อย่างไร ฉันไม่สามารถนึกถึงกรณีที่สิ่งนี้จะเป็นประโยชน์ ฉันรู้ว่าฉันสามารถหลีกเลี่ยงพฤติกรรมนี้ได้โดยใช้การเปรียบเทียบแบบไบนารี แต่ดูเหมือนจะเป็นวิธีที่แปลกในการใช้การเปรียบเทียบแบบเริ่มต้น
ตัวกรองหลักสร้าง caracters ที่ไม่ใช่ตัวเลข
ฉันสามารถสาธิตพฤติกรรมโดยการสร้างคอลัมน์ที่มีค่าอักขระไบต์เดียวที่เป็นไปได้ทั้งหมดและกรองค่าด้วยภาคแสดงการจับคู่ตัวเลข
คำสั่งต่อไปนี้สร้างตารางชั่วคราวที่มี 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 predicate และระบุช่วงของอักขระ '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