Esta questão não está tão relacionada aos bancos de dados, mas mais sobre o manuseio e as regras Unicode.
Com base em https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collation-name-transact-sql Latin1_General_100_CS_AS significa: "O agrupamento usa as regras de classificação geral do dicionário Latin1 e mapeia para a página de código 1252 "com CS = Sensível a maiúsculas e AS = Sensível a acentuação.
O mapeamento entre a página de código 1252 do Windows e o Unicode ( http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT ) mostra os mesmos valores para todos os caracteres com os quais estamos lidando (exceto e com macron que não existe no mapeamento da Microsoft; portanto, não faço ideia do que faz com este caso), para que possamos nos concentrar nas ferramentas e na terminologia Unicode por enquanto.
Primeiro, deixe-nos saber exatamente com o que estamos lidando, para todas as suas strings:
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
O algoritmo de agrupamento Unicode é descrito aqui: https://www.unicode.org/reports/tr10/
Veja a seção 1.3 "Sensibilidade contextual", que explica que a classificação não pode depender de apenas um caracter após o outro, pois algumas regras são sensíveis ao contexto.
Observe também estes pontos no 1.8:
O agrupamento não é uma propriedade de strings. A ordem de intercalação não é preservada em operações de concatenação ou substring, em geral.
Por padrão, o algoritmo utiliza três níveis totalmente personalizáveis. Para o script latino, esses níveis correspondem aproximadamente a:
alphabetic ordering
diacritic ordering
case ordering.
Mas o algoritmo por si só é um pouco denso. A essência é: Resumidamente, o Algoritmo de Collation Unicode usa uma string Unicode de entrada e uma Tabela de Elementos de Collation, contendo dados de mapeamento para caracteres. Produz uma chave de classificação, que é uma matriz de números inteiros de 16 bits não assinados. Duas ou mais chaves de classificação produzidas podem ser comparadas em binário para fornecer a comparação correta entre as strings para as quais foram geradas.
Você pode visualizar as regras específicas de classificação em latim aqui: http://developer.mimer.com/collations/charts/latin.htm
ou mais direta e especificamente para o MS SQL:
http://collation-charts.org/mssql/mssql. 0409.1252.Latin1_General_CS_AS.html
Para o e
personagem que mostra:
e E é Ééééééé
Isso explica seus resultados ao fazer o pedido, col1
exceto que ē não existe na página de códigos 1252, então não tenho absolutamente nenhuma idéia do que ele faz com ele.
Ou, se fizermos o algoritmo Unicode manualmente, usando o valor de chaves do DUCET em http://www.unicode.org/Public/UCA/latest/allkeys.txt :
etapa 1: Formulário de normalização D, para que cada caso se torne:
e => U+0065
é => U+0065 U+0301
ë => U+0065 U+0308
è => U+0065 U+0300
ê => U+0065 U+0302
ē => U+0065 U+0304
etapa 2, Produzir matrizes de agrupamento (pesquisa em arquivo 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]
etapa 3, Teclas de classificação de formulário (para cada nível, pegue cada valor dentro de cada matriz de agrupamento, coloque 0000 como delimitador e comece novamente para o próximo nível)
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
etapa 4, Compare as chaves de classificação (comparação binária simples de cada valor, uma por uma): O quarto valor é suficiente para classificar todas elas, portanto, a ordem final se torna:
e
é
è
ê
ë
ē
Da mesma maneira para fazer pedidos col2
:
passo 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
Etapa 2: Matrizes de agrupamento
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]
Etapa 3: Teclas de classificação de formulário
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
etapa 4: Compare as chaves de classificação: o segundo valor é suficiente para classificar todas elas e, de fato, já está em ordem crescente, portanto a ordem final é de fato:
eA
éB
ëC
èD
êE
ēF
Atualização : adicionando o terceiro caso de Solomon Rutzky, o que é mais complicado por causa do espaço que permite novas regras (eu escolhi o "caso não ignorável"):
etapa 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
Etapa 2, produzir matrizes de agrupamento:
è 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]
Etapa 3, chaves de classificação do formulário:
è 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
Etapa 4, compare as chaves de classificação:
Basicamente, o terceiro valor determina a ordem e, de fato, é apenas baseado no último dígito, portanto, a ordem deve ser:
è 1
e 2
ē 3
é 4
ê 5
ë 6
Segunda atualização com base no comentário de Solomon Rutzky sobre as versões Unicode.
Eu usei os allkeys.txt
dados sobre a versão mais recente do Unicode no momento, que é a versão 10.0
Se precisarmos considerar o Unicode 5.1 , este seria:
http://www.unicode.org/Public/UCA/5.1.0/allkeys.txt
Acabei de verificar, para todos os caracteres acima, as matrizes de agrupamento são as seguintes:
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]
e:
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]
e:
è 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 calculam as seguintes chaves de classificação:
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
e:
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
e:
è 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
o que novamente fornece esses três resultados classificados:
e
é
è
ê
ë
ē
e
eA
éB
ëC
èD
êE
ēF
e
è 1
e 2
ē 3
é 4
ê 5
ë 6
VARCHAR
(ou seja, não Unicode), que não estão sendo usados aqui. É por isso que oē
personagem funciona bem. 2) As informações dos gráficos de agrupamento estão um pouco desatualizadas. É para uma versão anterior deste agrupamento e eles não publicaram nada desde 2009. 3) A versão Unicode aqui definitivamente não é a mais recente (Versão 10). A_100_
série agrupamentos veio com SQL 2008, assim que esta seria Unicode 5.0 ou 5.1: unicode.org/standard/versions/#TUS_Earlier_VersionsallKeys.txt
mudanças entre a versão Unicode, além da adição de novos caracteres, portanto, o texto acima deveria permanecer verdadeiro, mas é claro que poderia ser refeito com os dados antigos anteriores, só me falta a energia de voltar a colocar algumas horas nele. Quanto ao CP1252, vinha apenas da definição dada pelo MS-SQL (eu não uso este produto).O comportamento que você está vendo aqui é devido, em um sentido geral, ao fato de o UCA (Unicode Collation Algorithm) permitir a classificação complexa em vários níveis. Mais especificamente:
A classificação não é comparação:
Determinar se duas strings são iguais ou diferentes é bastante direto (dado um local / idioma específico e um conjunto de sensibilidades). Mas determinar a ordem de 2 ou mais cadeias pode ser altamente complexo.
A classificação é feita em uma série de etapas, com cada etapa aplicada a toda a cadeia, não caractere por caractere:
Quando você classifica por
col1
(caractere único), primeiro ele determina que todos os caracteres têm o mesmo peso, pois são todos " e ". Em seguida, aplica os pesos sotaque / diacrítico. Não há diferenças de revestimento para que o terceiro passo não mude nada. Portanto, as únicas diferenças estão na etapa 2, e é por isso que há uma ordem preferida para essas linhas com base emcol1
.Quando você classifica por
col2
(dois caracteres), primeiro ele determina que cada linha tem um peso diferente, pois os dois caracteres são usados para determinar o peso da classificação (por exemplo, " ea ", " eb " etc.). Em seguida, aplica os pesos sotaque / diacrítico. Não há diferenças de revestimento para que o terceiro passo não mude nada. Portanto, existem diferenças nas etapas 1 e 2 neste momento. Mas como as diferenças na etapa 1 já foram aplicadas a cada corda antes que os pesos da etapa 2 sejam considerados, os pesos da etapa 2 não têm nenhum efeito sobre a ordem; eles seriam aplicados apenas se os pesos da etapa 1 para duas ou mais linhas fossem iguais.Esperamos que a seguinte adaptação do código de exemplo da pergunta ilustre o comportamento de classificação descrito acima. Adicionei algumas linhas adicionais e uma coluna adicional para ajudar a mostrar o impacto do agrupamento com distinção entre maiúsculas e minúsculas (já que os dados da amostra original são minúsculos):
CONFIGURAÇÃO
TESTE 1
Devoluções:
O que podemos ver nos resultados acima:
TESTE 2
Devoluções:
O que podemos ver nos resultados acima:
TESTE 3
Devoluções:
O que podemos ver nos resultados acima:
col2
da pergunta se deve novamente à "Comparação de vários níveis" e não à "Sensibilidade contextual".Notas Adicionais:
Com relação a obter as regras exatas, isso não é tão fácil quanto deveria ser. O problema de obter explicações concretas dessas regras é que as regras de classificação Unicode, embora definitivamente documentadas, são uma recomendação. Cabe a fornecedores, como a Microsoft, implementar essas recomendações. A Microsoft não implementou as recomendações exatamente como declaradas na documentação Unicode, para que haja uma desconexão (semelhante à forma como nem as especificações HTML ou CSS são implementadas de maneira tão completa, nem da mesma maneira, entre os fornecedores). Em seguida, existem versões diferentes dos agrupamentos do Windows (você está usando a versão lançada
100
com o SQL Server 2008) e está vinculada a uma versão Unicode muito mais antiga que a versão atual do Unicode ou a demonstração do ICU Collationestá usando. Por exemplo, a seção O que há de novo nos agrupamentos do SQL Server 2008 da documentação "Suporte para agrupamento e Unicode" do SQL Server 2008 destaca dois pontos muito interessantes sobre o que é "novo" para os_100_
agrupamentos da série:O Unicode 5.0 foi publicado em julho de 2006 (bem, o banco de dados de caracteres foi lançado na época e a especificação completa seguiu no final de 2006). A versão atual é 10.0, publicada em junho de 2017. E dado o padrão de lançamento dos últimos 4 anos, é provável que a versão 11.0 seja lançada em meados de 2018.
Esses pesos foram mais do que provavelmente definidos no Padrão Unicode, mas não nesta implementação.
Ainda assim, a documentação da UCA vinculada acima é um bom ponto de partida.
As chaves de classificação usadas pelo Windows / .NET / SQL Server não são exatamente as mesmas mostradas no padrão Unicode (consulte a resposta de @ Patrick) ou implementadas na UTI . Para ver o que o Windows / .NET / SQL Server usa, tente o método CompareInfo.GetSortKey . Eu criei um SQLCLR UDF para passar esses valores e obter a chave de classificação. Observe que estou usando o SQL Server 2017 no Windows 10 com o .NET Framework 4.5 - 4.6.1 instalado, portanto, o .NET deve usar o Unicode 6.0.0. Além disso, o Level4 não está sendo usado para essas seqüências.
Examinar essas chaves de classificação do Teste 1 e perceber que os níveis são classificados como várias colunas em uma
ORDER BY
cláusula (L3 é classificado com os mesmos valores de L2, classificados com os mesmos valores de L1), devem ilustrar que a razão do comportamento observado na pergunta é de fato o recurso de classificação em vários níveis do Unicode. Da mesma forma:Observando algumas das chaves de classificação do Teste 2, podemos ver que os caracteres base são classificados primeiro (L1), depois os acentos são classificados (L2) e, em seguida, o corpo (L3).
Como o tipo de dados é
NVARCHAR
, estamos preocupados apenas com os Pontos de Código Unicode e os algoritmos de classificação, portanto, o uso daUNICODE()
função no TESTE 1. Embora as Páginas de Código sejam especificadas pela maioria dos Collations, elas pertencem apenas aosVARCHAR
dados. Significado, enquanto o Código da Página 1252 é especificado pelaLatin1_General*
série de Agrupamentos, que pode ser ignorado aqui.Os pesos descritos na Tabela de elementos de agrupamento padrão Unicode (DUCET) ( versão 5.0.0, que deve ser mapeada para os agrupamentos em
_100_
série) são adequados para inglês dos EUA, mas não para outros locais / idiomas. Outros idiomas precisam iniciar com o DUCET e aplicar regras de substituição específicas do código do idioma, conforme definido pelo projeto Common Locale Data Repository (CLDR). Pelo que sei, as versões 1.4 / 1.4.1 foram lançadas em 2006. Para obter essas substituições, baixe o arquivo "core" do CLDR 1.4 em http://unicode.org/Public/cldr/1.4.0/core.zip , nesse arquivo zip, vá para a pasta de intercalação e localize o arquivo XML correspondente ao código do idioma que está sendo usado. Esses arquivos contêm apenas as substituições e não são conjuntos completos de regras de agrupamento.fonte