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 / 72641
Accepted
Faheem Mitha
Faheem Mitha
Asked: 2014-07-30 01:56:17 +0800 CST2014-07-30 01:56:17 +0800 CST 2014-07-30 01:56:17 +0800 CST

Verificando se duas tabelas têm conteúdo idêntico no PostgreSQL

  • 772

Isso já foi solicitado no Stack Overflow , mas apenas para o MySQL. Estou usando o PostgreSQL. Infelizmente (e surpreendentemente) o PostgreSQL não parece ter algo como CHECKSUM table.

Uma solução PostgreSQL seria boa, mas uma genérica seria melhor. Encontrei http://www.besttechtools.com/articles/article/sql-query-to-check-two-tables-have-identical-data , mas não entendo a lógica usada.

Background: Eu reescrevi algum código gerador de banco de dados, então preciso verificar se o código antigo e o novo produzem resultados idênticos.

postgresql duplication
  • 6 6 respostas
  • 97788 Views

6 respostas

  • Voted
  1. ypercubeᵀᴹ
    2014-07-30T02:09:07+08:002014-07-30T02:09:07+08:00

    Você pode usar o EXCEPToperador. Por exemplo, se as tabelas tiverem estrutura idêntica, o seguinte retornará todas as linhas que estão em uma tabela, mas não na outra (portanto, 0 linhas se as tabelas tiverem dados idênticos):

    (TABLE a EXCEPT TABLE b)
    UNION ALL
    (TABLE b EXCEPT TABLE a) ;
    

    Ou com EXISTSpara retornar apenas um valor booleano ou uma string com um dos 2 resultados possíveis:

    SELECT CASE WHEN EXISTS (TABLE a EXCEPT TABLE b)
                  OR EXISTS (TABLE b EXCEPT TABLE a)
                THEN 'different'
                ELSE 'same'
           END AS result ;
    

    Testado no SQLfiddle


    Também não é o que EXCEPTremove duplicatas (isso não deve ser uma preocupação se suas tabelas tiverem alguma PRIMARY KEYrestrição UNIQUE, mas pode ser se você estiver comparando resultados de consultas arbitrárias que podem produzir linhas duplicadas).

    Outra coisa que a palavra- EXCEPTchave faz é tratar NULLos valores como idênticos, portanto, se a tabela Ativer uma linha com (1,2,NULL)e a tabela Btiver uma linha com (1,2,NULL), a primeira consulta não mostrará essas linhas e a segunda consulta retornará 'same'se as duas tabelas não tiverem outra linha.

    Se você quiser contar essas linhas como diferentes, você pode usar uma variação na FULL JOINresposta do gsiems, para obter todas as linhas (diferentes):

    SELECT *
    FROM a NATURAL FULL JOIN b
    WHERE a.some_not_null_column IS NULL 
       OR b.some_not_null_column IS NULL ;
    

    e para obter uma resposta sim/não:

    SELECT CASE WHEN EXISTS
                ( SELECT *
                  FROM a NATURAL FULL JOIN b
                  WHERE a.some_not_null_column IS NULL 
                     OR b.some_not_null_column IS NULL
                )
                THEN 'different'
                ELSE 'same'
           END AS result ;
    

    Se todas as colunas das duas tabelas não forem anuláveis, as duas abordagens darão respostas idênticas.

    • 43
  2. Best Answer
    gsiems
    2014-07-30T06:11:53+08:002014-07-30T06:11:53+08:00

    Uma opção é usar um FULL OUTER JOIN entre as duas tabelas no seguinte formato:

    SELECT count (1)
        FROM table_a a
        FULL OUTER JOIN table_b b 
            USING (<list of columns to compare>)
        WHERE a.id IS NULL
            OR b.id IS NULL ;
    

    Por exemplo:

    CREATE TABLE a (id int, val text);
    INSERT INTO a VALUES (1, 'foo'), (2, 'bar');
    
    CREATE TABLE b (id int, val text);
    INSERT INTO b VALUES (1, 'foo'), (3, 'bar');
    
    SELECT count (1)
        FROM a
        FULL OUTER JOIN b 
            USING (id, val)
        WHERE a.id IS NULL
            OR b.id IS NULL ;
    

    Retornará uma contagem de 2, enquanto:

    CREATE TABLE a (id int, val text);
    INSERT INTO a VALUES (1, 'foo'), (2, 'bar');
    
    CREATE TABLE b (id int, val text);
    INSERT INTO b VALUES (1, 'foo'), (2, 'bar');
    
    SELECT count (1)
        FROM a
        FULL OUTER JOIN b 
            USING (id, val)
        WHERE a.id IS NULL
            OR b.id IS NULL ;
    

    retorna a contagem esperada de 0.

    A coisa que eu gosto sobre este método é que ele só precisa ler cada tabela uma vez versus ler cada tabela duas vezes ao usar EXISTS. Além disso, isso deve funcionar para qualquer banco de dados que suporte junções externas completas (não apenas Postgresql).

    Eu geralmente desencorajo o uso da cláusula USING, mas aqui está uma situação em que acredito ser a melhor abordagem.

    Adendo 2019-05-03:

    Se houver um problema com possíveis dados nulos (ou seja, a coluna id não é anulável, mas o val é), você pode tentar o seguinte:

    SELECT count (1)
        FROM a
        FULL OUTER JOIN b
            ON ( a.id = b.id
                AND a.val IS NOT DISTINCT FROM b.val )
        WHERE a.id IS NULL
            OR b.id IS NULL ;
    
    • 32
  3. Jelen
    2016-05-18T08:36:13+08:002016-05-18T08:36:13+08:00

    Você precisa da cláusula Except Algo como

    SELECT * FROM first_table
    EXCEPT
    SELECT * FROM second_table
    

    Isso retorna todas as linhas da primeira tabela que não estão na segunda tabela

    • 2
  4. Jack
    2020-11-11T11:21:58+08:002020-11-11T11:21:58+08:00

    Usar excepté a chave para encontrar o que está na tabela1 e não na tabela2 e vice-versa e unir os resultados. Se forem idênticos, a contagem é zero.

    ;with CTE1 AS
    (
      (
        select column1, column2 from Table1
        except
        select column1, column2 from Table2
      )
      UNION
      (
        select column1, column2 from Table2
        except
        select column1, column2 from Table1
      )
    )
    Select count(*) From CTE1  -- If identical count should be 0.
    
    • 1
  5. Michael Green
    2014-07-31T04:24:49+08:002014-07-31T04:24:49+08:00

    Se você não se importa com uma tabela ser menor que a outra, mas se importa apenas com as diferenças nos atributos:

    Olhando para o código vinculado que você não entende:

    select count(*) from
    (
    select * From EmpDtl1
    union
    select * From EmpDtl2
    )
    

    O molho secreto está usando unionem oposição a union all. O primeiro retém apenas linhas distintas, enquanto o último mantém duplicatas ( referência ). Em outras palavras, as consultas aninhadas dizem "me dê todas as linhas e colunas de EmpDtl1 e, além disso, aquelas de EmpDtl2 que ainda não estão em EmpDtl1". A contagem desta subconsulta será igual à contagem de EmpDtl1 se e somente se EmpDtl2 não contribuir com nenhuma linha para o resultado, ou seja, as duas tabelas são idênticas.

    Como alternativa, despeje as tabelas na sequência de teclas em dois arquivos de texto e use a ferramenta de comparação de sua escolha.

    • 0
  6. questionto42standswithUkraine
    2022-03-01T15:17:34+08:002022-03-01T15:17:34+08:00

    Gambiarra!

    Esta é uma solução alternativa para uma verificação rápida e não uma solução profissional. Ele está trabalhando apenas com colunas numéricas como identificadores, caso contrário, converta colunas de string em numéricas (conte as letras, converta em bytes ou similares) se necessário, e NULLs não são problema.

    Primeira solução não profissional: amostras

    No final, como as consultas demoravam muito em uma tabela de 1 Mio para serem comparadas com outras às vezes com valores NULL nos campos para cuidar também, peguei algumas amostras de números de linha escolhidos para testar a diferença de dois mesas aproximadamente. Eu não encontrei nenhuma diferença, pensando que eles são idênticos de qualquer maneira.

    Segunda solução um pouco mais profissional: sum() de colunas

    Embora essa amostra parecesse suficiente, eu queria ter certeza e, resumindo todas as colunas numéricas, encontrei diferenças!

    SELECT sum(col1), sum(col2) FROM table1
    UNION
    SELECT sum(col1), sum(col2) FROM table2
    

    A saída é como:

    soma(col1) soma(col2)
    11111345678 123456789101234
    11111123456 123456789101234

    Essa soma de colunas ou de toda a tabela é a verificação rápida, e normalmente já deve responder a pergunta principal e revela mais se você agrupar a tabela por atributos interessantes.

    Soma de verificação

    É um pouco como a solução CHECKSUM no MySQL .

    Mente: MySQL!! , não Postgresql:

    CHECKSUM TABLE original_table, backup_table;
    

    Você pode encontrar maneiras melhores em Como posso obter um hash de uma tabela inteira no postgresql? .

    A questão aqui é que é apenas um Hash, informações como no meu caso, quando eu pude ver pela soma da col1 que deve haver valores 0 ou NULL, se perde.

    Próximo passo: encontrar diferenças

    O próximo passo para encontrar as diferenças é então ordenar por col1 em ambas as tabelas, ou agrupar por - count() em col1 se não for único.

    Você também já deve saber quais atributos podem ser o problema e verificar que, no meu caso, sei que algum col1 pode ser 0. A soma de 0 não faz sentido, contando aqui, e a soma da outra coluna prova a diferença:

    SELECT count(col1), sum(col2) FROM table1 WHERE col1 = 0
    UNION
    SELECT count(col1), sum(col2) FROM table1 WHERE col1 = 0
    
    contagem(col1) soma(col2)
    1234 123456789
    345 6543210

    Uma contra-consulta:

    SELECT count(col1), sum(col2) FROM table1 WHERE col1 <> 0
    UNION
    SELECT count(col1), sum(col2) FROM table1 WHERE col1 <> 0
    

    e depois de algum tempo, você encontra os candidatos com alguma sorte ou depois de um grupo por visão geral que você pode verificar também subtraindo um do outro, ORDER BY difference DESC.

    Talvez execute consultas de longa duração agora

    Mas mesmo que você conheça scripts pesados ​​agora para encontrar as diferenças reais em uma verificação completa da mesa, você sabe pelo menos que esperar uma hora ou mais faz sentido. :)

    Pequena dica: selecione em uma nova tabela

    Pequena dica: se você executar uma consulta tão duradoura, considere a indexação primeiro. Além disso, verifique se você pode criar diretamente uma tabela dos resultados do sql usando

    CREATE TABLE MY_TABLE AS SELECT ...
    

    Para que você tenha os resultados não apenas na saída.

    • 0

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

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