O agrupamento padrão do meu servidor é Latin1_General_CI_AS, conforme determinado por esta consulta:
SELECT SERVERPROPERTY('Collation') AS Collation;
Fiquei surpreso ao descobrir que, com esse agrupamento, posso combinar caracteres que não são dígitos em cadeias usando o predicado LIKE '[0-9]'
.
Por que no agrupamento padrão isso acontece? Não consigo pensar em um caso em que isso seria útil. Eu sei que posso solucionar o comportamento usando um agrupamento binário, mas parece uma maneira estranha de implementar o agrupamento padrão.
A filtragem de dígitos produz caracteres que não são de dígitos
Eu posso demonstrar o comportamento criando uma coluna que contém todos os valores possíveis de caracteres de byte único e filtrando os valores com o predicado de correspondência de dígitos.
A instrução a seguir cria uma tabela temporária com 256 linhas, uma para cada ponto de código na página de código atual:
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;
Cada linha contém o valor inteiro do ponto de código e o valor de caractere do ponto de código. Nem todos os valores de caracteres são exibidos - alguns dos pontos de código são estritamente caracteres de controle. Aqui está uma amostra seletiva da saída de 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 ÿ
Eu esperaria poder filtrar na coluna Symbol para encontrar caracteres de dígito usando um predicado LIKE e especificando o intervalo de caracteres '0' a '9':
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';
Produz uma saída surpreendente:
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 ¾
O conjunto de pontos de código de 48 a 57 são os que eu espero. O que me surpreende é que os símbolos para sobrescritos e frações também estão incluídos no conjunto de resultados!
Pode haver uma razão matemática para pensar em expoentes e frações como números, mas parece errado chamá-los de dígitos.
Usando agrupamento binário como solução alternativa
Entendo que, para obter o resultado esperado, posso forçar o agrupamento binário correspondente Latin1_General_BIN:
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;
O conjunto de resultados inclui apenas os pontos de código 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
fonte