La clasificación predeterminada de mi servidor es Latin1_General_CI_AS, según lo determinado por esta consulta:
SELECT SERVERPROPERTY('Collation') AS Collation;
Me sorprendió descubrir que con esta clasificación puedo unir caracteres que no sean dígitos en cadenas usando el predicado LIKE '[0-9]'
.
¿Por qué en la clasificación predeterminada sucede esto? No puedo pensar en un caso en el que esto sea útil. Sé que puedo evitar el comportamiento utilizando una intercalación binaria, pero parece una forma extraña de implementar la intercalación predeterminada.
Filtrar dígitos produce caracteres que no son dígitos
Puedo demostrar el comportamiento creando una columna que contiene todos los valores posibles de caracteres de un solo byte y filtrando los valores con el predicado de coincidencia de dígitos.
La siguiente instrucción crea una tabla temporal con 256 filas, una para cada punto de código en la página de códigos actual:
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 fila contiene el valor entero del punto de código y el valor de carácter del punto de código. No todos los valores de caracteres son visualizables; algunos de los puntos de código son estrictamente caracteres de control. Aquí hay una muestra selectiva de la salida 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 ÿ
Esperaría poder filtrar en la columna Símbolo para encontrar caracteres de dígitos usando un predicado LIKE y especificando el rango de caracteres '0' a '9':
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';
Produce una salida 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 ¾
El conjunto de puntos de código 48 a 57 son los que espero. ¡Lo que me sorprende es que los símbolos para superíndices y fracciones también se incluyen en el conjunto de resultados!
Puede haber una razón matemática para pensar en exponentes y fracciones como números, pero parece incorrecto llamarlos dígitos.
Usar la intercalación binaria como solución alternativa
Entiendo que para obtener el resultado que espero, puedo forzar la colación binaria correspondiente Latin1_General_BIN:
SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;
El conjunto de resultados incluye solo los puntos 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
fuente