Bem, o problema é bem conhecido, mas estou procurando uma solução mais inteligente, se houver.
Por algum motivo o sistema não reconhece alguns caracteres e não consigo comparar as colunas
Segue um exemplo do texto:
Certo
ASPIRADOR ULTRASSONICO-LOCAÇAO (NOTA FISCAL SERVIÇO)
Errado
ASPIRADOR ULTRASSONICO-LOCA€AO (NOTA FISCAL SERVI€O)
Na verdade, estou corrigindo isso através desta função
create function fixcollation(@ps_Texto VARCHAR(4000)) returns VARCHAR(4000)
as
begin
declare @vlgsv1itu INT declare @nxn68ezzi INT declare @dw17rsyva VARCHAR(50) declare @iw8a2z01i VARCHAR(50) declare @t64e98xq6 VARCHAR(50) declare @zwjs2imy3 INT declare @jsyt85sy8 VARCHAR(4000)
----------------------------------------------------
set @dw17rsyva = ' …ƃ„µ·Ç¶Ž‚Šˆ‰ÔÒÓ¡‹ÖÞØ¢•ä“”àãå♣—–éëꚇ€§'
set @iw8a2z01i = 'áàãâäÁÀÃÂÄéèêëÈÉÊËíìïÍÌÏóòõôöÓÒÕÔÖúùûüÚÙÛÜçǺØ'
set @jsyt85sy8 = @ps_Texto set @zwjs2imy3 = IsNull(datalength(@ps_Texto), 0)
set @nxn68ezzi = 1
while(@nxn68ezzi <= IsNull(datalength( @ps_Texto), 0))
begin
set @vlgsv1itu = 1
while(@vlgsv1itu <= IsNull(datalength(@dw17rsyva), 0))
begin
IF(ASCII(SUBSTRING(@ps_Texto, @nxn68ezzi, 1) COLLATE LATIN1_GENERAL_CS_AS) = ASCII(SUBSTRING(@dw17rsyva, @vlgsv1itu, 1) COLLATE LATIN1_GENERAL_CS_AS))
BEGIN
set @t64e98xq6 = SUBSTRING( @iw8a2z01i, @vlgsv1itu, 1) set @jsyt85sy8 = SUBSTRING(@jsyt85sy8, 1, @nxn68ezzi -1) + @t64e98xq6 + SUBSTRING(@jsyt85sy8, @nxn68ezzi + 1, @zwjs2imy3 - @nxn68ezzi)
break
end
set @vlgsv1itu = @vlgsv1itu + 1
end
set @nxn68ezzi = @nxn68ezzi + 1
end
return @jsyt85sy8
end
Então, minha pergunta é: esse é o melhor caminho ou eu perdi alguma coisa aqui?
EDITAR
Apenas um teste complementar
select dbo.fixcollation(' …ƃ„µ·Ç¶Ž‚Šˆ‰ÔÒÓ¡‹ÖÞØ¢•ä“”àãå♣—–éëꚇ€§')
select dbo.FixCodePage850toCodePage1252(' …ƃ„µ·Ç¶Ž‚Šˆ‰ÔÒÓ¡‹ÖÞØ¢•ä“”àãå♣—–éëꚇ€§')
E este é o resultado no meu ambiente de produção
fixcollation
FixCodePage850toCodePage1252
Meus agradecimentos pessoais a Solomon Rutzky
Este é um problema de codificação incorreto. Os caracteres estão vindo codificados como página de código DOS 850, mas a página de código de destino que você está usando (com base nos
Latin1_General
agrupamentos) é a página de código 1252 do Windows. Por exemplo, na página de código DOS 850, oÇ
caractere tem um valor de 0x80 (ou 128 em Decimal). No entanto, esse mesmo valor de 0x80 na página de código do Windows 1252 fornece€
. Da mesma forma,Ã
em DOS Code Page 850 tem um valor de 0xC7 (ou 199 em Decimal). No entanto, esse mesmo valor de 0xC7 na página de código do Windows 1252 forneceÇ
.Os caracteres incorretos estão incorretos porque foram importados para o SQL Server com a codificação incorreta especificada para a origem. Isso não está acontecendo no SQL Server, pois seria um problema de conversão de página de código; nesse caso, o mesmo "caractere" teria seu valor traduzido para o mesmo caractere na página de código de destino (se o caractere existir na página de código de destino, senão você consegue
?
). Por exemplo:Devoluções:
Ou seja, isso está acontecendo provavelmente durante uma importação de arquivo - BCP.exe , SQLCMD.exe ,
BULK INSERT
,OPENROWSET(BULK...)
, código de aplicativo personalizado que lê um arquivo, etc - onde a página de código de origem errada está sendo especificada ou nenhuma página de código é especificado para a fonte. Se estiver sendo feita uma importação que especifica a página de código 1252 para este arquivo, ela terá o efeito que você está vendo aqui, pois esses bytes são codificados para a página de código 850, não a página de código 1252.Deve-se notar que isso também pode acontecer com dados vindos do código do aplicativo se o driver (ODBC, etc) estiver sendo instruído a usar a página de código errada.
Agora, sobre o método de correção disso:
SUBSTRING
carregar os caracteres, em pares, em uma variável de tabela que permitiria um único loop usando aREPLACE
função. E usar aASCII
função e um Collation sensível a maiúsculas e minúsculas é desnecessário e propenso a erros (se dois caracteres corresponderem ao que está sendo procurado) ao usar um_BIN2
Collation teria sido melhor.Use a seguinte função que faz a conversão. Primeiro ele pega os bytes da string atual, então ele injeta esses bytes em uma
VARCHAR
coluna que usa Code Page 850, então ele seleciona esse valor da variável de tabela em uma variável local (necessária de qualquer maneira para retornar o valor) que tem o efeito de convertendo a string na página de código usada pelo agrupamento padrão do banco de dados (que aqui teria que ser a página de código 1252, caso contrário você não estaria obtendo a string "correta" da função):Testar ambas as funções retorna os mesmos resultados:
Eu criei um teste para verificar os mapeamentos de todos os caracteres caso a empresa que fornece a função de tradução tenha perdido algum mapeamento. Eu filtrei os caracteres gráficos e o "i" sem ponto que são encontrados apenas na página de código 850.
Isso retorna uma lista de 52 caracteres que poderiam ter passado pelo processo de importação mal traduzidos como os outros, mas ignorados pela UDF que você foi fornecida por aquela outra empresa que lida apenas com 46 dos 98 caracteres aparentemente possíveis.