Classificação sensível ao acento

19

Por que essas duas SELECTinstruções resultam em uma ordem de classificação diferente?

USE tempdb;
CREATE TABLE dbo.OddSort 
(
    id INT IDENTITY(1,1) PRIMARY KEY
    , col1 NVARCHAR(2)
    , col2 NVARCHAR(2)
);
GO
INSERT dbo.OddSort (col1, col2) 
VALUES (N'e', N'eA')
    , (N'é', N'éB')
    , (N'ë', N'ëC')
    , (N'è', N'èD')
    , (N'ê', N'êE')
    , (N'ē', N'ēF');
GO

SELECT * 
FROM dbo.OddSort 
ORDER BY col1 COLLATE Latin1_General_100_CS_AS;
╔════╦══════╦══════╗
║ id ║ col1 ║ col2 ║
╠════╬══════╬══════╣
║ 1 ║ e ║ eA ║
║ 2 ║ é ║ éB ║
║ 4 è èD ║ - deve ser o id 3?
║ 5 ║ ê ║ êE ║
║ 3 C ë ëC ║
║ 6 ē ē ēF ║
╚════╩══════╩══════╝
SELECT * 
FROM dbo.OddSort 
ORDER BY col2 COLLATE Latin1_General_100_CS_AS;
╔════╦══════╦══════╗
║ id ║ col1 ║ col2 ║
╠════╬══════╬══════╣
║ 1 ║ e ║ eA ║
║ 2 ║ é ║ éB ║
║ 3 C ë ëC ║
║ 4 è è èD ║
║ 5 ║ ê ║ êE ║
║ 6 ē ē ēF ║
╚════╩══════╩══════╝
Aram
fonte

Respostas:

13

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 epersonagem que mostra:

e E é Ééééééé

Isso explica seus resultados ao fazer o pedido, col1exceto 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.txtdados 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
Patrick Mevzek
fonte
Oi Patrick. Obrigado por postar essas informações detalhadas. Algumas notas: 1) Você pode ignorar a Página de Código 1252. Isso é para dados 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_Versions
Solomon Rutzky
Eu não acho que as allKeys.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).
Patrick Mevzek 12/0318
1) Provavelmente não há grandes mudanças entre as versões, mas tenho quase certeza de que há correções de peso / classificação, no mínimo. Mas sim, certamente recebo restrições de tempo;) 2) Em relação ao CP1252, eu o mencionei porque o conceito de páginas de código não existe no Unicode. Unicode é um meio de nunca precisar de páginas de código. O documento da Microsoft não é claro sobre isso, mas menciona no topo " A página de código usada para armazenar dados de caracteres não Unicode ". Você está certo de que o único personagem não está no CP1252, mas as Páginas de Código não entram em cena aqui.
Solomon Rutzky
Sim, eu nunca disse nada sobre a página de código relacionada ao Unicode. É apenas a documentação do MS SQL que diz que esse nome de agrupamento funciona com a "página de código 1252". Provavelmente não faz sentido (não para mim, mas novamente, não é um usuário), mas é o que está escrito na documentação deste software. Quanto a refazer o trabalho, fique à vontade para fazê-lo ou apenas forneça as alterações sobre a classificação relacionadas aos personagens em jogo aqui entre o Unicode 5 e o mais recente, se houver e se desejar. Acredito que minha resposta permaneça como é, é precisa e constrói os resultados com base nas informações, e não o contrário.
Patrick Mevzek
3) re: frase 1: embora principalmente sobre Unicode, essa questão seja um problema do SO, pois a MS implementou as especificações e pode não ter feito tudo isso e / ou pode ter cometido alguns erros. Eu encontrei dois erros no .NET sobre como ele determina a "categoria" ou o "bloco" em que um caractere específico está (eles identificaram incorretamente um pequeno segmento de caracteres). Além disso, esse é , pelo menos um pouco, um problema do SQL Server, apenas porque o SQL Server possui efetivamente um instantâneo de cada agrupamento em um determinado momento (para consistência entre versões), para que eles possam ter o que é agora o comportamento específico do SQL Server.
Solomon Rutzky 31 /
16

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:

  1. 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.

  2. A classificação é feita em uma série de etapas, com cada etapa aplicada a toda a cadeia, não caractere por caractere:

    1. Padrão: classifica os caracteres base (independentemente das diferenças de acento e maiúsculas)
    2. SE sensível ao acento, aplique pesos acentuados / diacríticos
    3. Se for sensível a maiúsculas e minúsculas, aplique pesos de revestimento

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 em col1.

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

USE [tempdb];

-- DROP TABLE dbo.OddSort;
CREATE TABLE dbo.OddSort
(
    id INT IDENTITY(1,1) PRIMARY KEY,
    col1 NVARCHAR(5) COLLATE Latin1_General_100_CS_AS,
    col2 NVARCHAR(5) COLLATE Latin1_General_100_CS_AS,
    col3 NVARCHAR(5) COLLATE Latin1_General_100_CS_AS
);
GO

INSERT dbo.OddSort (col1, col2, col3)
VALUES (N'e', N'eA', N'e A')
     , (N'ê', N'êE', N'ê E')
     , (N'é', N'éH', N'é H')
     , (N'ë', N'ëC', N'ë C')
     , (N'E', N'EG', N'E G')
     , (N'Ë', N'ëh', N'ë h')
     , (N'è', N'èD', N'è D')
     , (N'é', N'éB', N'é B')
     , (N'ë', N'ëH', N'ë H')
     , (N'ē', N'ēF', N'ē F');

TESTE 1

SELECT [id], [col1], UNICODE([col1]) AS [CodePoint]
FROM dbo.OddSort 
ORDER BY col1;

Devoluções:

id    col1    CodePoint
1     e       101
5     E       69
8     é       233
3     é       233
7     è       232
2     ê       234
4     ë       235
9     ë       235
6     Ë       203
10    ē       275

O que podemos ver nos resultados acima:

  1. O ponto de código não está determinando a ordem de classificação
  2. Os caracteres não acentuados são classificados antes dos caracteres acentuados (dentro da mesma letra: f ainda viria depois de tudo isso). Claramente, os pesos de acento são aplicados antes dos pesos de caixa.
  3. Classificações em minúsculas antes de maiúsculas no mesmo caractere acentuado (ou não acentuado) (ou seja, e então E , e ë então Ë ). Essa adaptação é usada pela maioria dos agrupamentos do Windows, enquanto a maioria dos agrupamentos do SQL Server classifica primeiro em maiúsculas.

TESTE 2

SELECT [id], [col2]
FROM dbo.OddSort 
ORDER BY col2;

Devoluções:

id    col2
1     eA
8     éB
4     ëC
7     èD
2     êE
10    ēF
5     EG
3     éH
6     ëh
9     ëH

O que podemos ver nos resultados acima:

  1. A classificação de primeiro nível é realmente os caracteres base. Se fossem acentos / diacríticos, as linhas ëC (id = 4), ēF (id = 10) e EG (id = 5) não estariam onde estão. Se estivesse em caixa, a linha EG (id = 5) não estaria onde está.
  2. A classificação de segundo nível é realmente os acentos / diacríticos. Isso explica por que as últimas três linhas são éH -> ëh -> ëH em vez de ëh -> éH -> ÊH (ou seja, IDs 3 -> 6 -> 9 em vez de 6 -> 3 -> 9).
  3. A classificação de terceiro nível é verdadeiramente a caixa. É por isso que as duas últimas linhas são ëh -> ëH , pois as minúsculas são as primeiras.

TESTE 3

SELECT [id], [col3]
FROM dbo.OddSort 
ORDER BY col3;

Devoluções:

id    col3
1     e A
8     é B
4     ë C
7     è D
2     ê E
10    ē F
5     E G
3     é H
6     ë h
9     ë H

O que podemos ver nos resultados acima:

  1. A ordem de classificação é exatamente a mesma do Teste 2. A única diferença nos valores de teste aqui é que há um espaço entre cada caractere, removendo a possibilidade de regras contextuais. Portanto, sabemos que o motivo da diferença na ordem de classificação col2da pergunta se deve novamente à "Comparação de vários níveis" e não à "Sensibilidade contextual".

Notas Adicionais:

  1. 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 100com 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:

    1. Tabela de casos Unicode 5.0.

      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.

    2. A ponderação foi adicionada aos caracteres anteriormente não ponderados que teriam sido comparados igualmente.

      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.

  2. 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.

    CHAR    L1     L2     L3     L4
    e      0E21
    E      0E21           12
    ë      0E21    13
    Ë      0E21    13     12

    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 BYclá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:

    CHAR       L1         L2       L3       L4
    EG      0E210E25              1212
    éH      0E210E2C      0E      0212
    ëh      0E210E2C      13
    ëH      0E210E2C      13      0212

    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).

  3. 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 da UNICODE()função no TESTE 1. Embora as Páginas de Código sejam especificadas pela maioria dos Collations, elas pertencem apenas aos VARCHARdados. Significado, enquanto o Código da Página 1252 é especificado pela Latin1_General*série de Agrupamentos, que pode ser ignorado aqui.

  4. 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.

Solomon Rutzky
fonte