it-swarm.com.de

Überprüfen, ob zwei Tabellen in PostgreSQL identischen Inhalt haben

Dies war bereits bei Stack Overflow gefragt , aber nur für MySQL. Ich benutze PostgreSQL. Leider (und überraschenderweise) scheint PostgreSQL nicht so etwas wie CHECKSUM table .

Eine PostgreSQL-Lösung wäre in Ordnung, eine generische wäre jedoch besser. Ich habe http://www.besttechtools.com/articles/article/sql-query-to-check-two-tables-have-identical-data gefunden, aber ich verstehe die verwendete Logik nicht .

Hintergrund: Ich habe einen Code zum Generieren von Datenbanken neu geschrieben, daher muss ich überprüfen, ob der alte und der neue Code identische Ergebnisse liefern.

29
Faheem Mitha

Eine Möglichkeit besteht darin, einen FULL OUTER JOIN zwischen den beiden Tabellen in der folgenden Form zu verwenden:

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 ;

Zum Beispiel:

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 ;

Gibt eine Zählung von 2 zurück, während:

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 ;

gibt die erhoffte Anzahl von 0 zurück.

Das, was mir an dieser Methode gefällt, ist, dass sie jede Tabelle nur einmal lesen muss, während sie bei Verwendung von EXISTS jede Tabelle zweimal liest. Darüber hinaus sollte dies für jede Datenbank funktionieren, die vollständige äußere Verknüpfungen unterstützt (nicht nur Postgresql).

Ich rate generell von der Verwendung der USING-Klausel ab, aber hier ist eine Situation, in der ich glaube, dass dies der bessere Ansatz ist.

Nachtrag 2019-05-03 :

Wenn ein Problem mit möglichen Nulldaten vorliegt (d. H. Die ID-Spalte ist nicht nullwertfähig, der Wert jedoch), können Sie Folgendes versuchen:

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

Sie können den Operator EXCEPT verwenden. Wenn die Tabellen beispielsweise eine identische Struktur haben, werden im Folgenden alle Zeilen zurückgegeben, die sich in einer Tabelle befinden, jedoch nicht in der anderen (also 0 Zeilen, wenn die Tabellen identische Daten enthalten):

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

Oder mit EXISTS, um nur einen booleschen Wert oder eine Zeichenfolge mit einem der beiden möglichen Ergebnisse zurückzugeben:

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

Getestet bei SQLfiddle


Auch nicht das, dass EXCEPT Duplikate entfernt (das sollte keine Sorge sein, wenn Ihre Tabellen eine Einschränkung von PRIMARY KEY Oder UNIQUE haben, aber es kann sein, dass Sie Ergebnisse beliebiger Abfragen vergleichen das kann möglicherweise doppelte Zeilen erzeugen).

Eine andere Sache, die das Schlüsselwort EXCEPT tut, ist, dass es NULL -Werte als identisch behandelt. Wenn also Tabelle A eine Zeile mit (1,2,NULL) Und Tabelle B hat eine Zeile mit (1,2,NULL), die erste Abfrage zeigt diese Zeilen nicht an und die zweite Abfrage gibt 'same' zurück, wenn die beiden Tabellen keine andere Zeile haben.

Wenn Sie solche Zeilen als unterschiedlich zählen möchten, können Sie eine Variation der Antwort von gsiems FULL JOIN Verwenden, um alle (unterschiedlichen) Zeilen zu erhalten:

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

und um eine Ja/Nein-Antwort zu erhalten:

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 ;

Wenn nicht alle Spalten der beiden Tabellen nullwertfähig sind, geben die beiden Ansätze identische Antworten.

31
ypercubeᵀᴹ

Sie benötigen eine Ausnahmeklausel

SELECT * FROM first_table
EXCEPT
SELECT * FROM second_table

Dies gibt alle Zeilen aus der ersten Tabelle zurück, die nicht in der zweiten Tabelle enthalten sind

1
Jelen

Wenn Sie sich den verknüpften Code ansehen, verstehen Sie Folgendes nicht:

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

Die geheime Sauce verwendet union im Gegensatz zu union all. Ersteres behält nur unterschiedliche Zeilen bei, während letzteres Duplikate enthält ( Referenz ). Mit anderen Worten, in den verschachtelten Abfragen heißt es "Geben Sie mir alle Zeilen und Spalten von EmpDtl1 und zusätzlich diejenigen von EmpDtl2, die noch nicht in EmpDtl1 enthalten sind". Die Anzahl dieser Unterabfrage ist genau dann gleich der Anzahl von EmpDtl1, wenn EmpDtl2 keine Zeilen zum Ergebnis beiträgt, d. H. Die beiden Tabellen sind identisch.

Alternativ können Sie die Tabellen in Schlüsselreihenfolge in zwei Textdateien speichern und das Vergleichstool Ihrer Wahl verwenden.

0
Michael Green