web-dev-qa-db-ja.com

PostgreSQLで2つのテーブルの内容が同じかどうかを確認する

これはすでに Stack Overflowで尋ねられました ですが、MySQL専用です。 PostgreSQLを使用しています。残念ながら(そして意外にも)PostgreSQLには CHECKSUM table

PostgreSQLソリューションは問題ありませんが、一般的なソリューションの方が優れています。 http://www.besttechtools.com/articles/article/sql-query-to-check-two-tables-have-identical-data が見つかりましたが、使用されているロジックがわかりません。

背景:データベースを生成するコードを書き直したので、古いコードと新しいコードが同じ結果になるかどうかを確認する必要があります。

29
Faheem Mitha

1つのオプションは、次の形式で2つのテーブル間でFULL OUTER JOINを使用することです。

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 ;

例えば:

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 ;

一方、2のカウントを返します。

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 ;

期待されるカウント0を返します。

この方法について私が気に入っているのは、EXISTSを使用する場合、各テーブルを1回だけ読み取るのに対して、各テーブルを2回読み取る必要があることです。さらに、これは(Postgresqlだけでなく)完全外部結合をサポートするすべてのデータベースで機能します。

私は一般的にUSING句の使用を推奨しませんが、これがより良いアプローチであると私が信じる状況の1つです。

追記2019-05-03:

Nullデータの可能性に問題がある場合(つまり、id列はnull可能ではありませんが、valは可能です)、次のことを試すことができます。

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 ;
24
gsiems

EXCEPT演算子を使用できます。たとえば、テーブルの構造が同じ場合、次の例では、1つのテーブルにあるが他のテーブルにはないすべての行を返します(テーブルに同じデータがある場合は0行です)。

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

または、EXISTSを使用して、ブール値または2つの可能な結果の1つを含む文字列のみを返します。

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

SQLfiddle でテスト


また、EXCEPTが重複を削除するわけではありません(テーブルに_PRIMARY KEY_またはUNIQUE制約がある場合は心配する必要はありませんが、重複する行を生成する可能性のある任意のクエリの結果を比較している場合もあります)。

EXCEPTキーワードのもう1つのことは、NULLの値を同じものとして扱うため、テーブルAに_(1,2,NULL)_の行があり、テーブルBに_(1,2,NULL)_の行がある場合、最初のクエリではこれらの行が表示されず、 2つのテーブルに他の行がない場合、2番目のクエリは_'same'_を返します。

そのような行を異なるものとしてカウントしたい場合は、gsiemsの_FULL JOIN_の回答のバリエーションを使用して、すべての(異なる)行を取得できます。

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

はい/いいえの答えを得るには:

_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 ;
_

2つのテーブルのすべての列がNULL可能ではない場合、2つのアプローチは同じ答えを与えます。

31
ypercubeᵀᴹ

Except句が必要です

SELECT * FROM first_table
EXCEPT
SELECT * FROM second_table

これは、2番目のテーブルにない最初のテーブルのすべての行を返します

1
Jelen

理解できないリンクされたコードを見る:

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

秘密のソースはunion allではなくunionを使用しています。前者は異なる行のみを保持しますが、後者は重複を保持します( 参照 )。言い換えると、ネストされたクエリは、「EmpDtl1からのすべての行と列、およびまだEmpDtl1にないEmpDtl2からの行と列を取得してください」と言います。 EmpDtl2が結果に行を提供しない場合、つまり2つのテーブルが同一である場合にのみ、このサブクエリの数はEmpDtl1の数と等しくなります。

または、キーシーケンスのテーブルを2つのテキストファイルにダンプし、選択した比較ツールを使用します。

0
Michael Green