जाँच कर रहा है कि क्या PostgreSQL में दो तालिकाओं में समान सामग्री है


28

यह पहले से ही स्टैक ओवरफ्लो पर पूछा गया है , लेकिन केवल MySQL के लिए। मैं PostgreSQL का उपयोग कर रहा हूं। दुर्भाग्य से (और आश्चर्यजनक रूप से) PostgreSQL को ऐसा कुछ नहीं लगता है CHECKSUM table

एक PostgreSQL समाधान ठीक होगा, लेकिन एक सामान्य एक बेहतर होगा। मुझे http://www.besttechtools.com/articles/article/sql-query-to-check-two-tables-have-identical-data मिला है , लेकिन मुझे समझ में नहीं आता कि तर्क का इस्तेमाल किया।

पृष्ठभूमि: मैंने कुछ डेटाबेस जनरेटिंग कोड को फिर से लिखा है, इसलिए मुझे यह जांचने की आवश्यकता है कि क्या पुराने और नए कोड समान परिणाम उत्पन्न करते हैं।



pg_comparator कुशल तालिका सामग्री तुलना और तुल्यकालन करता है
natmaka

@natmaka क्या यह एक अलग उत्तर होना चाहिए?
फहीम मीठा

जवाबों:


24

एक विकल्प निम्न रूप में दो तालिकाओं के बीच एक पूर्ण OOO 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 का उपयोग करना पड़ता है। इसके अतिरिक्त, यह किसी भी डेटाबेस के लिए काम करना चाहिए जो पूर्ण बाहरी जोड़ का समर्थन करता है (न कि सिर्फ पोस्टग्रैस्कल)।

मैं आमतौर पर इस्तेमाल करने वाले खंड का उपयोग करने को हतोत्साहित करता हूं, लेकिन यहां एक ऐसी स्थिति है जहां मैं इसे बेहतर दृष्टिकोण मानता हूं।

परिशिष्ट 2019-05-03:

यदि कोई संभावित अशक्त डेटा के साथ कोई समस्या है, (यानी आईडी कॉलम अशक्त नहीं है, लेकिन वैल है) तो आप निम्न कार्य नहीं कर सकते हैं:

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 ;

यदि घाटी अशक्त है तो क्या यह विफल नहीं होगा?
अमित गोल्डस्टीन

@AmitGoldstein - नल एक समस्या होगी। उस के लिए एक संभव समाधान के लिए मेरा परिशिष्ट देखें।
gsiems

30

आप EXCEPTऑपरेटर का उपयोग कर सकते हैं । उदाहरण के लिए, यदि तालिकाओं में समान संरचना है, तो निम्नलिखित सभी पंक्तियाँ वापस आ जाएंगी जो एक तालिका में हैं, लेकिन अन्य नहीं (इसलिए यदि तालिका में समान डेटा है तो 0 पंक्तियाँ):

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

या EXISTS2 संभावित परिणामों में से एक के साथ सिर्फ एक बूलियन मान या एक स्ट्रिंग वापस करने के लिए:

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कीवर्ड करता है वह यह है कि यह NULLमानों को समान मानता है , इसलिए यदि तालिका Aमें एक पंक्ति है (1,2,NULL)और तालिका के Bसाथ एक पंक्ति है (1,2,NULL), तो पहली क्वेरी इन पंक्तियों को नहीं दिखाएगी और दूसरी क्वेरी वापस आ जाएगी 'same'यदि दोनों तालिकाओं में कोई अन्य पंक्ति नहीं है।

यदि आप ऐसी पंक्तियों को अलग-अलग गिनना चाहते हैं, तो आप FULL JOINसभी (भिन्न) पंक्तियों को प्राप्त करने के लिए, gsiems के उत्तर पर भिन्नता का उपयोग कर सकते हैं :

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 ;

यदि दो तालिकाओं के सभी कॉलम अशक्त नहीं हैं, तो दोनों दृष्टिकोण समान उत्तर देंगे।


कुछ और कुशल विधि हो सकती है, निश्चित नहीं।
ypercube y

@FaheemMitha आप सभी से कम कॉलम की तुलना करने के लिए इसका उपयोग कर सकते हैं। SELECT <column_list> FROM aइसके बजाय का उपयोग करेंTABLE a
ypercubeᵀᴹ

2
EXCEPTक्वेरी एक beaut है!
एरविन ब्रान्डस्टेट्टर

एक्सक्लूसिव क्वेरी प्यारी है!
शारदोव

1

आपको क्लॉज के अलावा कुछ चाहिए

SELECT * FROM first_table
EXCEPT
SELECT * FROM second_table

यह पहली तालिका से सभी पंक्तियों को लौटाता है जो दूसरी तालिका में नहीं हैं


0

लिंक किए गए कोड को देखकर आपको समझ में नहीं आता है:

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

गुप्त चटनी के unionविपरीत उपयोग कर रहा है union all। पूर्व केवल अलग-अलग पंक्तियों को बरकरार रखता है जबकि बाद वाला डुप्लिकेट ( संदर्भ ) रखता है । दूसरे शब्दों में नेस्टेड क्वेरीज़ कहती है "मुझे EmpDtl1 से सभी पंक्तियाँ और कॉलम दें और इसके अलावा EmpDtl2 से जो पहले से ही EmpDtl1 में नहीं हैं"। इस उपकुंजी की गिनती EmpDtl1 की गिनती के बराबर होगी यदि और केवल अगर EmpDtl2 परिणाम के लिए किसी भी पंक्तियों में योगदान नहीं करता है अर्थात दोनों तालिकाएं समान हैं।

वैकल्पिक रूप से, दो पाठ फ़ाइलों के लिए कुंजी क्रम में तालिकाओं को डंप करें और अपनी पसंद के तुलना उपकरण का उपयोग करें।


3
यह उस स्थिति का पता नहीं लगाएगा, जब EmpDtl2इससे कम पंक्तियाँ हों EmpDtl1और सभी मौजूदा पंक्तियाँ मौजूद हों EmpDtl1
a_horse_with_no_name
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.