O ponto de código Unicode 9619 é um caractere chamado "Tonalidade escura": ▓
( http://unicode-table.com/en/search/?q=9619 ).
Usando o SQL_Latin1_General_CP1_CI_AS
agrupamento e a página de código 1252, eu esperaria que a conversão / conversão desse caractere Unicode para o tipo de dados não Unicode resultasse em um ponto de interrogação ( ?
), pois a página de código 1252 não parece conter esse caractere e isso parece ser do SQL Server comportamento quando a conversão não pode ocorrer.
Então, minha pergunta é: por que o SQL Server converte esse caractere em um código ASCII 166 que é "Pipe, Broken vertical bar" ¦
:?
SELECT NCHAR(9619), CAST(NCHAR(9619) AS CHAR(1)), ASCII(CAST(NCHAR(9619) AS CHAR(1)))
sql-server
collation
encoding
unicode
Henry Lee
fonte
fonte
Respostas:
O SQL Server não está empregando nenhuma lógica personalizada especial aqui; está usando serviços padrão do sistema operacional para executar a conversão.
Especificamente, o serviço de tipo e expressão do SQL Server (
sqlTsEs
) chama a rotina do SOWideCharToMultiByte
emkernel32.dll
. O SQL Server define os parâmetros de entrada paraWideCharToMultiByte
que a rotina execute uma 'tradução rápida'. Isso é mais rápido do que solicitar que um caractere padrão específico seja usado quando não houver tradução direta.A tradução rápida se baseia na página de código de destino para executar um mapeamento mais adequado para caracteres sem correspondência, conforme mencionado no link que Martin Smith forneceu em um comentário à pergunta:
Quando os parâmetros de entrada são definidos para uma tradução rápida,
WideCharToMultiByte
chama o serviço do SOGetMBNoDefault
( origem ). A inspeção da pilha de chamadas do SQL Server ao executar a conversão especificada na pergunta confirma isso:fonte
A conversão de dados Unicode em uma página de código específica emprega a estratégia conhecida como "Melhor ajuste" (conforme observado na resposta de @ Paul e no link que @Martin anotou em um comentário sobre a Pergunta). De acordo com a página do MSDN para codificação de caracteres no .NET Framework :
Mas o que exatamente são esses mapeamentos? Essa página do MSDN costumava indicar o seguinte:
No entanto, isso não estava totalmente correto. Talvez as "estratégias" para determinar os mapeamentos não estejam exatamente documentadas. Está bem. Mas, os próprios mapeamentos são documentados, mas não nos lugares mais fáceis de encontrar.
Portanto, graças à Microsoft movendo a documentação para o GitHub, essa página agora declara o seguinte (porque eu a atualizei):
Se você for para o URL a seguir, verá uma lista de vários arquivos, cada um nomeado para a Página de Código para a qual mapeia caracteres Unicode:
ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/
A maioria dos arquivos foi atualizada pela última vez (ou pelo menos foi colocada lá) em 04/10/2006, e um deles foi atualizado em 14/03/2012. A primeira parte desses arquivos mapeia códigos ASCII em um ponto de código Unicode equivalente. Mas a segunda parte de cada arquivo mapeia os caracteres Unicode em seus "equivalentes" ASCII.
Eu escrevi um script de teste que usa os mapeamentos de código para verificar se o SQL Server está realmente usando esses mapeamentos. Isso pode ser determinado respondendo a essas duas perguntas:
?
caractere " " não " "?O script de teste é muito longo para ser colocado aqui, então eu o publiquei no Pastebin em:
Mapeamentos Unicode para Página de Código no SQL Server
A execução do script mostrará que a resposta para a primeira pergunta acima é "Sim" (significando que todos os mapeamentos fornecidos são respeitados). Também mostrará que a resposta para a segunda pergunta é "Não" (ou seja, nenhum dos Pontos de código não mapeados se converte em nada além do caractere "desconhecido"). Portanto, esse arquivo de mapeamento é muito preciso :-).
fonte