Le regole di confronto predefinite del mio server sono Latin1_General_CI_AS, come determinato da questa query:
SELECT SERVERPROPERTY('Collation') AS Collation;
Sono stato sorpreso di scoprire che con questo confronto posso abbinare caratteri non numerici nelle stringhe usando il predicato LIKE '[0-9]'
.
Perché nelle regole di confronto predefinite succede? Non riesco a pensare a un caso in cui questo sarebbe utile. So di poter aggirare il comportamento utilizzando una raccolta binaria, ma sembra uno strano modo di implementare la raccolta predefinita.
Il filtraggio delle cifre produce caratteri non numerici
Posso dimostrare il comportamento creando una colonna che contiene tutti i possibili valori dei caratteri a byte singolo e filtrando i valori con il predicato di corrispondenza delle cifre.
La seguente istruzione crea una tabella temporanea con 256 righe, una per ogni punto di codice nella tabella codici corrente:
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;
Ogni riga contiene il valore intero del punto di codice e il valore del carattere del punto di codice. Non tutti i valori dei caratteri sono visualizzabili - alcuni dei punti del codice sono rigorosamente caratteri di controllo. Ecco un esempio selettivo dell'output di 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 ÿ
Mi aspetterei di poter filtrare nella colonna Simbolo per trovare caratteri numerici usando un predicato LIKE e specificando l'intervallo di caratteri da '0' a '9':
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';
Produce un risultato sorprendente:
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 ¾
L'insieme di punti di codice da 48 a 57 sono quelli che mi aspetto. Ciò che mi sorprende è che i simboli per apice e frazioni siano inclusi anche nel set di risultati!
Potrebbe esserci una ragione matematica per pensare agli esponenti e alle frazioni come numeri, ma sembra sbagliato chiamarli cifre.
Utilizzo delle regole di confronto binarie come soluzione alternativa
Capisco che per ottenere il risultato che mi aspetto, posso forzare la corrispondenza binaria corrispondente Latin1_General_BIN:
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;
Il set di risultati include solo i punti di codice da 48 a 57:
CodePoint Symbol
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9