Esta pregunta no está tan relacionada con las bases de datos, sino más sobre el manejo y las reglas de Unicode.
Basado en https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql Latin1_General_100_CS_AS significa: "La clasificación utiliza las reglas y mapas de clasificación general del diccionario Latin1 en la página de códigos 1252 "con el agregado CS = mayúsculas y minúsculas y AS = acento sensible.
La asignación entre la página de códigos de Windows 1252 y Unicode ( http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT ) muestra los mismos valores para todos los caracteres con los que estamos tratando (excepto e con macron eso no existe en el mapeo de Microsoft, así que no tengo idea de qué hace con este caso), por lo que podemos concentrarnos en las herramientas y la terminología de Unicode por ahora.
Primero, háganos saber con precisión a qué nos enfrentamos, para todas sus cadenas:
0065 LATIN SMALL LETTER E
0041 LATIN CAPITAL LETTER A
00E9 LATIN SMALL LETTER E WITH ACUTE
0042 LATIN CAPITAL LETTER B
00EB LATIN SMALL LETTER E WITH DIAERESIS
0043 LATIN CAPITAL LETTER C
00E8 LATIN SMALL LETTER E WITH GRAVE
0044 LATIN CAPITAL LETTER D
00EA LATIN SMALL LETTER E WITH CIRCUMFLEX
0045 LATIN CAPITAL LETTER E
0113 LATIN SMALL LETTER E WITH MACRON
0046 LATIN CAPITAL LETTER F
El algoritmo de colación Unicode se describe aquí: https://www.unicode.org/reports/tr10/
Eche un vistazo a la sección 1.3 "Sensibilidad contextual" que explica que la clasificación no puede depender de un solo carácter después del otro, ya que algunas reglas son sensibles al contexto.
Tenga en cuenta también estos puntos en 1.8:
La clasificación no es una propiedad de cadenas. El orden de clasificación no se conserva bajo operaciones de concatenación o subcadena, en general.
Por defecto, el algoritmo utiliza tres niveles totalmente personalizables. Para la escritura latina, estos niveles corresponden aproximadamente a:
alphabetic ordering
diacritic ordering
case ordering.
Pero el algoritmo en sí mismo es un poco denso. La esencia de esto es: En pocas palabras, el Algoritmo de clasificación Unicode toma una cadena Unicode de entrada y una Tabla de elementos de clasificación, que contiene datos de mapeo para los caracteres. Produce una clave de clasificación, que es una matriz de enteros de 16 bits sin signo. Dos o más claves de clasificación así producidas se pueden comparar en binario para dar la comparación correcta entre las cadenas para las que se generaron.
Puede ver las reglas específicas de clasificación en latín aquí: http://developer.mimer.com/collations/charts/latin.htm
o más directa y específicamente para MS SQL:
http://collation-charts.org/mssql/mssql. 0409.1252.Latin1_General_CS_AS.html
Para el e
personaje que muestra:
e E é É è È ê Ê ë Ë
Esto explica sus resultados al realizar el pedido, col1
excepto que ē no existe en la página de códigos 1252, por lo que no tengo absolutamente ninguna idea de lo que hace con él.
O si hacemos el algoritmo Unicode a mano, utilizando el valor de las claves de DUCET en http://www.unicode.org/Public/UCA/latest/allkeys.txt :
Paso 1: Forma de normalización D, por lo que cada caso se convierte en:
e => U+0065
é => U+0065 U+0301
ë => U+0065 U+0308
è => U+0065 U+0300
ê => U+0065 U+0302
ē => U+0065 U+0304
paso 2, Producir matrices de intercalación (búsqueda en archivo allkeys.txt
)
e => [.1D10.0020.0002]
é => [.1D10.0020.0002] [.0000.0024.0002]
ë => [.1D10.0020.0002] [.0000.002B.0002]
è => [.1D10.0020.0002] [.0000.0025.0002]
ê => [.1D10.0020.0002] [.0000.0027.0002]
ē => [.1D10.0020.0002] [.0000.0032.0002]
paso 3, Forme las claves de clasificación (para cada nivel, tome cada valor dentro de cada matriz de clasificación, luego coloque 0000 como delimitador y comience nuevamente para el siguiente nivel)
e => 1D10 0000 0020 0000 0002
é => 1D10 0000 0020 0024 0000 0002 0002
ë => 1D10 0000 0020 002B 0000 0002 0002
è => 1D10 0000 0020 0025 0000 0002 0002
ê => 1D10 0000 0020 0027 0000 0002 0002
ē => 1D10 0000 0020 0032 0000 0002 0002
Paso 4, Comparar claves de clasificación (comparación binaria simple de cada valor uno por uno): el cuarto valor es suficiente para ordenarlos todos, por lo que el orden final se convierte en:
e
é
è
ê
ë
ē
De la misma manera para ordenar col2
:
paso 1: NFD
eA => U+0065 U+0041
éB => U+0065 U+0301 U+0042
ëC => U+0065 U+0308 U+0043
èD => U+0065 U+0300 U+0044
êE => U+0065 U+0302 U+0045
ēF => U+0065 U+0304 U+0046
paso 2: matrices de intercalación
eA => [.1D10.0020.0002] [.1CAD.0020.0008]
éB => [.1D10.0020.0002] [.0000.0024.0002] [.1CC6.0020.0008]
ëC => [.1D10.0020.0002] [.0000.002B.0002] [.1CE0.0020.0008]
èD => [.1D10.0020.0002] [.0000.0025.0002] [.1CF5.0020.0008]
êE => [.1D10.0020.0002] [.0000.0027.0002] [.1D10.0020.0008]
ēF => [.1D10.0020.0002] [.0000.0032.0002] [.1D4B.0020.0008]
Paso 3: claves de clasificación de formulario
eA => 1D10 1CAD 0000 0020 0020 0000 0002 0008
éB => 1D10 1CC6 0000 0020 0024 0020 0000 0002 0002 0008
ëC => 1D10 1CE0 0000 0020 002B 0020 0000 0002 0002 0008
èD => 1D10 1CF5 0000 0020 0025 0020 0000 0002 0002 0008
êE => 1D10 1D10 0000 0020 0027 0020 0000 0002 0002 0008
ēF => 1D10 1D4B 0000 0020 0032 0020 0000 0002 0002 0008
Paso 4: Comparar las claves de clasificación: el segundo valor es suficiente para ordenarlas todas, y de hecho ya está en orden creciente, por lo que el orden final es:
eA
éB
ëC
èD
êE
ēF
Actualización : agregar el tercer caso de Solomon Rutzky, que es más complicado debido al espacio que permite nuevas reglas (elegí el "caso no ignorable"):
paso 1, NFD:
è 1 => U+0065 U+0300 U+0020 U+0031
ê 5 => U+0065 U+0302 U+0020 U+0035
e 2 => U+0065 U+0020 U+0032
é 4 => U+0065 U+0301 U+0020 U+0034
ē 3 => U+0065 U+0304 U+0020 U+0033
ë 6 => U+0065 U+0308 U+0020 U+0036
Paso 2, Producir matrices de intercalación:
è 1 => [.1D10.0020.0002] [.0000.0025.0002] [*0209.0020.0002] [.1CA4.0020.0002]
ê 5 => [.1D10.0020.0002] [.0000.0027.0002] [*0209.0020.0002] [.1CA8.0020.0002]
e 2 => [.1D10.0020.0002] [*0209.0020.0002] [.1CA5.0020.0002]
é 4 => [.1D10.0020.0002] [.0000.0024.0002] [*0209.0020.0002] [.1CA7.0020.0002]
ē 3 => [.1D10.0020.0002] [.0000.0032.0002] [*0209.0020.0002] [.1CA6.0020.0002]
ë 6 => [.1D10.0020.0002] [.0000.002B.0002] [*0209.0020.0002] [.1CA9.0020.0002]
Paso 3, claves de clasificación de formulario:
è 1 => 1D10 0209 1CA4 0000 0020 0025 0020 0020 0000 0002 0002 0002 0002
ê 5 => 1D10 0209 1CA8 0000 0020 0027 0020 0020 0000 0002 0002 0002 0002
e 2 => 1D10 0209 1CA5 0000 0020 0020 0020 0000 0002 0002 0002
é 4 => 1D10 0209 1CA7 0000 0020 0024 0020 0020 0000 0002 0002 0002 0002
ē 3 => 1D10 0209 1CA6 0000 0020 0032 0020 0020 0000 0002 0002 0002 0002
ë 6 => 1D10 0209 1CA9 0000 0020 002B 0020 0020 0000 0002 0002 0002 0002
Paso 4, compara las claves de clasificación:
Básicamente, el tercer valor determina el orden, y de hecho solo se basa en el último dígito, por lo que el orden debería ser:
è 1
e 2
ē 3
é 4
ê 5
ë 6
Segunda actualización basada en el comentario de Solomon Rutzky sobre las versiones de Unicode.
Usé los allkeys.txt
datos sobre la última versión de Unicode en este momento, es decir, la versión 10.0
Si necesitamos tener en cuenta Unicode 5.1 , esto sería:
http://www.unicode.org/Public/UCA/5.1.0/allkeys.txt
Acabo de comprobar, para todos los caracteres anteriores, las matrices de intercalación son las siguientes:
e => [.119D.0020.0002.0065]
é => [.119D.0020.0002.0065] [.0000.0032.0002.0301]
ë => [.119D.0020.0002.0065] [.0000.0047.0002.0308]
è => [.119D.0020.0002.0065] [.0000.0035.0002.0300]
ê => [.119D.0020.0002.0065] [.0000.003C.0002.0302]
ē => [.119D.0020.0002.0065] [.0000.005B.0002.0304]
y:
eA => [.119D.0020.0002.0065] [.1141.0020.0008.0041]
éB => [.119D.0020.0002.0065] [.0000.0032.0002.0301] [.1157.0020.0008.0042]
ëC => [.119D.0020.0002.0065] [.0000.0047.0002.0308] [.116F.0020.0008.0043]
èD => [.119D.0020.0002.0065] [.0000.0035.0002.0300] [.1182.0020.0008.0044]
êE => [.119D.0020.0002.0065] [.0000.003C.0002.0302] [.119D.0020.0008.0045]
ēF => [.119D.0020.0002.0065] [.0000.005B.0002.0304] [.11D5.0020.0008.0046]
y:
è 1 => [.119D.0020.0002.0065] [.0000.0035.0002.0300] [*0209.0020.0002.0020] [.1138.0020.0002.0031]
ê 5 => [.119D.0020.0002.0065] [.0000.003C.0002.0302] [*0209.0020.0002.0020] [.113C.0020.0002.0035]
e 2 => [.119D.0020.0002.0065] [*0209.0020.0002.0020] [.1139.0020.0002.0032]
é 4 => [.119D.0020.0002.0065] [.0000.0032.0002.0301] [*0209.0020.0002.0020] [.113B.0020.0002.0034]
ē 3 => [.119D.0020.0002.0065] [.0000.005B.0002.0304] [*0209.0020.0002.0020] [.113A.0020.0002.0033]
ë 6 => [.119D.0020.0002.0065] [.0000.0047.0002.0308] [*0209.0020.0002.0020] [.113D.0020.0002.0036]
que luego se calculan con las siguientes claves de clasificación:
e => 119D 0000 0020 0000 0002 0000 0065
é => 119D 0000 0020 0032 0000 0002 0002 0000 0065 0301
ë => 119D 0000 0020 0047 0000 0002 0002 0000 0065 0308
è => 119D 0000 0020 0035 0000 0002 0002 0000 0065 0300
ê => 119D 0000 0020 003C 0000 0002 0002 0000 0065 0302
ē => 119D 0000 0020 005B 0000 0002 0002 0000 0065 0304
y:
eA => 119D 1141 0000 0020 0020 0000 0002 0008 0000 0065 0041
éB => 119D 1157 0000 0020 0032 0020 0000 0002 0002 0008 0000 0065 0301 0042
ëC => 119D 116F 0000 0020 0047 0020 0000 0002 0002 0008 0000 0065 0308 0043
èD => 119D 1182 0000 0020 0035 0020 0000 0002 0002 0008 0000 0065 0300 0044
êE => 119D 119D 0000 0020 003C 0020 0000 0002 0002 0008 0000 0065 0302 0045
ēF => 119D 11D5 0000 0020 005B 0020 0000 0002 0002 0008 0000 0065 0304 0046
y:
è 1 => 119D 0209 1138 0000 0020 0035 0020 0020 0000 0002 0002 0002 0002 0000 0065 0300 0020 0031
ê 5 => 119D 0209 113C 0000 0020 003C 0020 0020 0000 0002 0002 0002 0002 0000 0065 0302 0020 0035
e 2 => 119D 0209 1139 0000 0020 0020 0020 0000 0002 0002 0002 0000 0065 0020 0032
é 4 => 119D 0209 113B 0000 0020 0032 0020 0020 0000 0002 0002 0002 0002 0000 0065 0301 0020 0034
ē 3 => 119D 0209 113A 0000 0020 005B 0020 0020 0000 0002 0002 0002 0002 0000 0065 0304 0020 0033
ë 6 => 119D 0209 113D 0000 0020 0047 0020 0020 0000 0002 0002 0002 0002 0000 0065 0308 0020 0036
que nuevamente da estos tres resultados ordenados:
e
é
è
ê
ë
ē
y
eA
éB
ëC
èD
êE
ēF
y
è 1
e 2
ē 3
é 4
ê 5
ë 6
VARCHAR
(es decir, no Unicode), que no se utilizan aquí. Es por eso que elē
personaje funciona bien. 2) La información de "gráficos de colación" está un poco desactualizada. Es para una versión anterior de esta Clasificación y no han publicado nada desde 2009. 3) La versión Unicode aquí definitivamente no es la última (Versión 10). La_100_
serie Collations llegó con SQL 2008, por lo que sería Unicode 5.0 o 5.1: unicode.org/standard/versions/#TUS_Earlier_VersionsallKeys.txt
cambios entre la versión Unicode, además de la adición de nuevos caracteres, por lo que lo anterior deba seguir siendo cierto pero, por supuesto, podría rehacerse con los datos anteriores anteriores, solo me falta la energía de volver a dedicar algunas horas. En cuanto a CP1252, solo provenía de la definición dada por MS-SQL (no uso este producto yo mismo).El comportamiento que está viendo aquí se debe, en un sentido general, al hecho de que el Algoritmo de clasificación Unicode (UCA) permite una ordenación compleja de niveles múltiples. Más específicamente:
Ordenar no es comparación:
Determinar si dos cadenas son iguales o diferentes es bastante sencillo (dado un entorno / idioma particular y un conjunto de sensibilidades). Pero determinar el orden de 2 o más cadenas puede ser muy complejo.
La clasificación se realiza en una serie de pasos, con cada paso aplicado a toda la cadena, no carácter por carácter:
Cuando ordena por
col1
(carácter único), primero determina que todos los caracteres tienen el mismo peso ya que son todos " e ". Luego, aplica el acento / peso diacrítico. No hay diferencias de carcasa, por lo que el tercer paso no cambiaría nada. Entonces, las únicas diferencias están en el paso 2, por lo que hay un orden preferido para esas filas en funcióncol1
.Cuando ordena por
col2
(dos caracteres), primero determina que cada fila tiene un peso diferente, ya que ambos caracteres se utilizan para determinar el peso de clasificación (por ejemplo, " ea ", " eb ", etc.). Luego, aplica el acento / peso diacrítico. No hay diferencias de carcasa, por lo que el tercer paso no cambiaría nada. Entonces, hay diferencias en los pasos 1 y 2 esta vez. Pero dado que las diferencias en el paso 1 ya se han aplicado a cada cadena antes de considerar los pesos del paso 2, los pesos del paso 2 no tienen ningún efecto en el orden; solo se aplicarían si los pesos del paso 1 para dos o más filas fueran iguales.La siguiente adaptación del código de muestra de la pregunta, con suerte, ilustra el comportamiento de clasificación descrito anteriormente. Agregué algunas filas adicionales y una columna adicional para ayudar a mostrar el impacto de la clasificación que distingue entre mayúsculas y minúsculas (ya que los datos de la muestra original son minúsculas):
PREPARAR
PRUEBA 1
Devoluciones:
Lo que podemos ver en los resultados anteriores:
PRUEBA 2
Devoluciones:
Lo que podemos ver en los resultados anteriores:
PRUEBA 3
Devoluciones:
Lo que podemos ver en los resultados anteriores:
col2
la pregunta se debe nuevamente a la "Comparación multinivel" y no a la "Sensibilidad contextual".Notas adicionales:
Con respecto a obtener las reglas exactas, eso no es tan fácil como debería ser. El problema para obtener explicaciones concretas de estas reglas es que las reglas de clasificación Unicode, aunque definitivamente están documentadas, son una recomendación. Depende de los proveedores, como Microsoft, implementar esas recomendaciones. Microsoft no implementó las recomendaciones exactamente como se indica en la documentación de Unicode, por lo que hay una desconexión allí (similar a cómo ni las especificaciones HTML o CSS se implementan completamente, ni siquiera de la misma manera, en todos los proveedores). Luego, hay diferentes versiones de las intercalaciones de Windows (está utilizando la versión
100
que salió con SQL Server 2008) y que está vinculada a una versión Unicode que es mucho más antigua que la versión actual de Unicode o de la demostración de colación ICUesta usando. Por ejemplo, la sección Novedades en las colaciones de SQL Server 2008 de la documentación "Compatibilidad y compatibilidad con Unicode" para SQL Server 2008 presenta dos puntos muy interesantes sobre lo que es "nuevo" en la_100_
serie Colaciones:Unicode 5.0 se publicó en julio de 2006 (bueno, la base de datos de personajes se lanzó entonces, y la especificación completa siguió a fines de 2006). La versión actual es la 10.0 que se publicó en junio de 2017. Y dado el patrón de lanzamiento de los últimos 4 años, es probable que la versión 11.0 salga en algún momento a mediados de 2018.
Esos pesos probablemente se definieron en el estándar Unicode, pero no en esta implementación del mismo.
Aún así, la documentación de UCA vinculada anteriormente es un buen lugar para comenzar.
Las claves de clasificación utilizadas por Windows / .NET / SQL Server no son exactamente las mismas que se muestran en el estándar Unicode (ver la respuesta de @ Patrick) o implementadas en la UCI . Para ver qué uso de Windows / .NET / SQL Server, puede probar el método CompareInfo.GetSortKey . Creé un UDF SQLCLR para pasar estos valores y obtener la clave de clasificación. Tenga en cuenta que estoy usando SQL Server 2017 en Windows 10 con .NET Framework 4.5 - 4.6.1 instalado, por lo que .NET debería usar Unicode 6.0.0. Además, Level4 no se está utilizando para estas cadenas.
Observar estas claves de clasificación para la Prueba 1 y darse cuenta de que los niveles se clasifican como columnas múltiples dentro de una
ORDER BY
cláusula (L3 se clasifica dentro de los mismos valores de L2, que se clasifica dentro de los mismos valores de L1), debería ilustrar que la razón del comportamiento En la pregunta se señala, de hecho, la capacidad de clasificación de varios niveles de Unicode. Igualmente:Al observar algunas de las teclas de clasificación para la Prueba 2, podemos ver que los caracteres base se ordenan primero (L1), luego se ordenan los acentos (L2) y luego se ordena la carcasa (L3).
Dado que el tipo de datos es
NVARCHAR
, solo nos interesan los puntos de código Unicode y los algoritmos de clasificación, de ahí el uso de laUNICODE()
función en TEST 1. Si bien la mayoría de las colaciones especifican páginas de códigos, solo se refieren aVARCHAR
datos. Es decir, aunque la página de códigos 1252 está especificada por laLatin1_General*
serie de intercalaciones, eso puede ignorarse aquí.Los pesos descritos en la Tabla de elementos de clasificación Unicode predeterminada (DUCET) ( Versión 5.0.0 que debería correlacionarse con las
_100_
Series de clasificación) están bien para el inglés de EE. UU., Pero no para otros idiomas / idiomas. Otros idiomas deben comenzar con el DUCET y luego aplicar reglas de anulación específicas de la configuración regional según lo definido por el proyecto del Repositorio de datos de configuración regional común (CLDR). Por lo que puedo decir, las versiones 1.4 / 1.4.1 se lanzaron en 2006. Para obtener esas anulaciones, descargue el archivo "núcleo" CLDR 1.4 a través de http://unicode.org/Public/cldr/1.4.0/core.zip , luego, en ese archivo zip, vaya a la carpeta de intercalación y busque el archivo XML correspondiente a la configuración regional que se está utilizando. Esos archivos contienen solo las anulaciones y no son conjuntos completos de reglas de clasificación.fuente