PostgreSQL'de iki tablonun aynı içeriğe sahip olup olmadığını kontrol etme


28

Bu zaten Stack Overflow'ta istendi , fakat sadece MySQL için. PostgreSQL kullanıyorum. Ne yazık ki (ve şaşırtıcı bir şekilde) PostgreSQL gibi bir şeye sahip görünmüyorCHECKSUM table .

PostgreSQL çözümü iyi olurdu, ancak genel olan daha iyi olurdu. Http://www.besttechtools.com/articles/article/sql-query-to-check-two-tables-have-identical-data'yı buldum , ancak kullanılan mantığı anlamıyorum.

Arka plan: Bazı veritabanı üreten kodları yeniden yazdım, bu nedenle eski ve yeni kodun aynı sonuçları sağlayıp sağlamadığını kontrol etmem gerekiyor.


3
Kullanabilirsiniz, EXCEPTbu soruyu kontrol edin:
SQL'deki

pg_comparator verimli tablo içeriği karşılaştırma ve senkronizasyonu yapıyor
natmaka 25:17

@ natmaka Bu ayrı bir cevap mı olmalı?
Faheem Mitha

Yanıtlar:


24

Bir seçenek, aşağıdaki biçimde iki tablo arasında bir TAM OUTER JOIN kullanmaktır:

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 ;

Örneğin:

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 ;

Oysa 2 sayısı döndürür:

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 sayısının umudunu döndürür.

Bu yöntemle ilgili hoşuma giden şey, EXISTS kullanırken her bir tabloyu yalnızca bir kez okumak yerine her tabloyu iki kez okumak olması gerektiğidir. Ek olarak, bu, tam dış birleşmeleri destekleyen herhangi bir veritabanı için çalışmalıdır (sadece Postgresql değil).

Genellikle KULLANIM yantümcesinin kullanılmasını önermem ama bu daha iyi bir yaklaşım olduğuna inandığım bir durum.

Ek 2019-05-03:

Olası boş verilerle ilgili bir sorun varsa (yani, id sütunu geçersiz sayılmaz ancak val olur), sonra aşağıdakileri deneyebilirsiniz:

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 ;

Val null ise bu başarısız olmaz mıydı?
Amit Goldstein

@AmitGoldstein - boş bir sorun olacaktır. Bunun olası bir çözümü için ekime bakınız.
gsiems,

30

EXCEPTOperatörü kullanabilirsiniz . Örneğin, tablolar aynı yapıya sahipse, aşağıdakiler bir tabloda bulunan ancak diğerinde olmayan tüm satırları döndürür (yani, tablolarda aynı veriler varsa 0 satır):

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

Veya EXISTSyalnızca bir boolean değeri veya olası 2 sonuçtan birine sahip bir dize döndürmek için:

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

SQLfiddle'da Test Edildi


Ayrıca, bu EXCEPTyinelenenleri kaldırmaz (tablolarınızda bazıları varsa endişelenmemesi gereken PRIMARY KEYveyaUNIQUE kısıtlaması ancak yinelenen satırları üretebilecek isteğe bağlı sorguların sonuçlarını karşılaştırıyorsanız olabilir).

EXCEPTAnahtar kelimenin yaptığı başka bir şey de NULLdeğerleri aynı olarak ele almasıdır, bu nedenle eğer tablo Abir satırla birlikte (1,2,NULL)ve Bsatırın bir satır ile birlikte olması durumunda (1,2,NULL), ilk sorgu bu satırları göstermeyecek ve ikinci sorgu 'same'iki tablo başka bir satır içermiyorsa geri dönecektir .

Eğer bu gibi satırları farklı olarak saymak istiyorsanız FULL JOIN, tüm (farklı) satırları almak için , gsiems'in cevabında bir varyasyon kullanabilirsiniz :

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

ve evet / hayır cevabı almak için:

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 ;

İki tablonun tüm sütunları null yapılamazsa, iki yaklaşım aynı cevapları verecektir.


Emin değilim, daha verimli bir yöntem olabilir.
ypercubeᵀᴹ

@FaheemMitha Bunu, hepsinden daha az sütunu karşılaştırmak için kullanabilirsiniz. Sadece SELECT <column_list> FROM ayerine kullanınTABLE a
ypercubeᵀᴹ

2
EXCEPTSorgu bir beaut olduğunu!
Erwin Brandstetter 1

İSTATİSTİK sorgu tatlı!
sharadov

1

Bir fıkra hariç

SELECT * FROM first_table
EXCEPT
SELECT * FROM second_table

Bu, ikinci tabloda olmayan ilk tablodaki tüm satırları döndürür.


0

Bağlantılı koda bakarak anlamadığınız:

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

Gizli sos unionaksine kullanıyor union all. İlki, yalnızca farklı satırları tutarken, ikincisi kopyaları tutar ( başvuru ). Başka bir deyişle, iç içe geçmiş querys "bana EmpDtl1 ve ek olarak EmpDtl1’de olmayan EmpDtl2’den tüm satırları ve sütunları ver" diyor. Bu alt sorgunun sayısı, eğer sadece EmpDtl2 sonuç için herhangi bir sıraya katkıda bulunmuyorsa, yani iki tablo aynı ise EmpDtl1'in sayısına eşit olacaktır.

Alternatif olarak, tabloları anahtar sırayla iki metin dosyasına atın ve karşılaştırma aracınızı kullanın.


3
Bu durum, varolan tüm satırların içinde olduğundan EmpDtl2daha az satır olduğunda EmpDtl1ve durumu algılamaz EmpDtl1.
a_horse_with_no_name
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.