AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 197263
Accepted
Krismorte
Krismorte
Asked: 2018-02-08 04:36:09 +0800 CST2018-02-08 04:36:09 +0800 CST 2018-02-08 04:36:09 +0800 CST

Agrupar problemas com caracteres errados

  • 772

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

insira a descrição da imagem aqui

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(' …ƃ„µ·Ç¶Ž‚Šˆ‰ÔÒÓ¡‹ÖÞØ¢•ä“”àãå♣—–éëꚇ€§')

insira a descrição da imagem aqui

E este é o resultado no meu ambiente de produção

fixcollation

insira a descrição da imagem aqui

FixCodePage850toCodePage1252

insira a descrição da imagem aqui

Meus agradecimentos pessoais a Solomon Rutzky

sql-server t-sql
  • 1 1 respostas
  • 1753 Views

1 respostas

  • Voted
  1. Best Answer
    Solomon Rutzky
    2018-02-08T09:46:07+08:002018-02-08T09:46:07+08:00

    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_Generalagrupamentos) é 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:

    SELECT ASCII('Ç' COLLATE Latin1_General_CI_AS) AS [CP1252 Value],
           'Ç' COLLATE SQL_Latin1_General_CP850_CI_AS AS [CharacterInCP850],
           ASCII('Ç' COLLATE SQL_Latin1_General_CP850_CI_AS) AS [CP850 Value];
    

    Devoluções:

    CP1252 Value     CharacterInCP850     CP850 Value
    199              Ç                    128
    

    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:

    1. Idealmente, o método de importação dos dados seria atualizado/fixado para contabilizar adequadamente a página de código real com a qual os dados foram codificados.
    2. Se não for possível corrigir o processo de importação, a função que a outra empresa forneceu não é o melhor caminho a seguir. Na verdade, é provavelmente a abordagem mais lenta e complicada que também é propensa a erros (se eles não mapearam todos os caracteres). Não há razão para fazer dois loops ao SUBSTRINGcarregar os caracteres, em pares, em uma variável de tabela que permitiria um único loop usando a REPLACEfunção. E usar a ASCIIfunçã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 _BIN2Collation teria sido melhor.
    3. 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 VARCHARcoluna 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):

      USE [tempdb];
      GO
      CREATE FUNCTION dbo.FixCodePage850toCodePage1252
      (
          @CodePage850String VARCHAR(8000)
      )
      RETURNS VARCHAR(8000)
      WITH SCHEMABINDING
      AS
      BEGIN
        DECLARE @Convert850to1252 TABLE
        (
          [String] VARCHAR(8000) COLLATE SQL_Latin1_General_CP850_CI_AS
        );
        DECLARE @ReturnValue VARCHAR(8000);
      
        INSERT INTO @Convert850to1252 ([String])
        VALUES (CONVERT(VARBINARY(8000), @CodePage850String, 0));
      
        SELECT @ReturnValue = [String] -- automatic conversion to Code Page of database
        FROM @Convert850to1252;
      
        RETURN @ReturnValue;
      END;
      GO
      

      Testar ambas as funções retorna os mesmos resultados:

      SELECT dbo.fixcollation('lj§ ULTRASSONICO-LOCA€AO (NOTA SERVI€O)');
      -- Ãëº ULTRASSONICO-LOCAÇAO (NOTA SERVIÇO)
      
      SELECT dbo.FixCodePage850toCodePage1252('lj§ ULTRASSONICO-LOCA€AO (NOTA SERVI€O)');
      -- Ãëº ULTRASSONICO-LOCAÇAO (NOTA SERVIÇO)
      

    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.

    USE [tempdb];
    GO
    ;WITH nums AS
    (
        SELECT TOP (256) (ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1) AS [num]
        FROM   master.sys.columns
    ), vals AS
    (
      SELECT nums.[num] AS [Value],
             CHAR(nums.[num]) AS [Character],
             dbo.fixcollation(CHAR(nums.[num])) AS [OldWay],
             dbo.FixCodePage850toCodePage1252(CHAR(nums.[num])) AS [NewWay]
      FROM   nums
    )
    SELECT vals.*,
           ASCII(vals.[NewWay]) AS [NewValue]
    FROM   vals
    WHERE  vals.[Character] <> vals.[NewWay] COLLATE Latin1_General_BIN2
    AND    vals.[OldWay] <> vals.[NewWay] COLLATE Latin1_General_BIN2
    AND    vals.[Value] NOT IN (176, 177, 178, 179, 180, 185, 186, 187, 188,
                                191, 192, 193, 194, 195, 196, 197, 200, 201,
                                202, 203, 204, 205, 206, 217, 218, 219, 220,
                                223, 254, 213); -- characters only in CP850
    

    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.

    • 10

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve