मुझे psycopg2 का उपयोग करके एक पोस्टग्रेएसक्यूएल डेटाबेस में एक साथ कई पंक्तियों (INSERT ... ON CONFLICT DO UPDATE) को ऊपर उठाने की आवश्यकता है। अनिवार्य रूप से, मेरे पास "पंक्तियों" का प्रतिनिधित्व करने वाले टुपल्स की एक सूची है, और मुझे उन्हें डेटाबेस में डालने की आवश्यकता है, या यदि कोई विरोध है तो डेटाबेस को अपडेट करें। मुझे (संभवतः) प्रत्येक कॉलम को अद्यतन करने की आवश्यकता है (यदि सम्मिलित नहीं है), प्रत्येक पंक्ति के साथ।

मैंने psycopg2 के cursor.execute() फ़ंक्शन और execute_many() फ़ंक्शन का उपयोग करके दो मुख्य तरीकों की कोशिश की है। सबसे पहले, मैंने निम्नलिखित किया:

upsert_statement = 'INSERT INTO table (col1, col2, col3) VALUES %s ON CONFLICT (col1) DO UPDATE SET (col1, col2, col3) = ROW (excluded.*) WHERE table IS DISTINCT FROM excluded'

psycopg2.extras.execute_values(cursor, upsert_statement, values)

मैं एक एसक्यूएल स्टेटमेंट बनाता हूं जो execute_many() (जहां values को पास किया गया है, टुपल्स की एक सूची है) का उपयोग करके मान सम्मिलित करता है, और एक संघर्ष पर कॉलम मानों को अपवर्जित करने के लिए अद्यतन किया जाना चाहिए। हालांकि, मुझे त्रुटि मिलती है SyntaxError: number of columns does not match number of values कभी-कभी, भले ही मैं एक तथ्य के लिए जानता हूं कि स्तंभों और मानों की संख्या समान है।

इसलिए, मैंने केवल execute() का उपयोग करने का प्रयास किया:

upsert_statement = f'INSERT INTO table (col1, col2, col3) VALUES (value1, value2, value3), (value4, value5, value6)... ON CONFLICT (col1) DO UPDATE SET (col1, col2, col3) = (value1, value2, value3), (value4, value5, value6)...'

cursor.execute(upsert_statement)

यहां, मैं SQL के हिस्से के रूप में बैच अप्सर्ट करता हूं, और इसलिए execute_values() का उपयोग करने की आवश्यकता नहीं है। हालांकि, मुझे DO UPDATE SET के बाद एक SyntaxError मिलता है, क्योंकि मुझे नहीं लगता कि यह (col1, col2, col3) = (value1, value2, value3), (value4, value5, value6)... होना मान्य है।

मैं क्या गलत कर रहा हूं? मैं psycopg2 का उपयोग करके एकाधिक पंक्तियों को कैसे बढ़ा सकता हूं?

(मुझे ध्यान देना चाहिए कि वास्तव में, (col1, col2, col3) और (value1, value2, value3) गतिशील हैं, और अक्सर बदलते रहते हैं)

0
jack.py 22 नवम्बर 2021, 16:48

1 उत्तर

सबसे बढ़िया उत्तर

आपको table EXCLUDED का इस्तेमाल करें। यह डालने के लिए प्रस्तावित एक विशेष टेबल होल्डिंग मान है। आपको परस्पर विरोधी मूल्यों को फिर से सेट करने की आवश्यकता नहीं है, केवल शेष।

INSERT INTO table (col1, col2, col3) 
VALUES 
    (value1, value2, value3), 
    (value4, value5, value6)
ON CONFLICT (col1) DO UPDATE 
SET (col2, col3) = (EXCLUDED.col2, EXCLUDED.col3);

पठनीयता के लिए, यदि आप अपने एफ-स्ट्रिंग्स को ट्रिपल-कोट करते हैं तो आप अपने इन-लाइन एसक्यूएल को प्रारूपित कर सकते हैं। मुझे यकीन नहीं है कि क्या और कौन से आईडीई यह पता लगा सकते हैं कि यह पाइथन में एक इन-लाइन एसक्यूएल है और सिंटैक्स हाइलाइटिंग स्विच करता है, लेकिन मुझे इंडेंटेशन काफी मददगार लगता है।

upsert_statement = f"""
    INSERT INTO table (col1, col2, col3) 
    VALUES 
        ({value1}, {value2}, {value3}), 
        ({value4}, {value5}, {value6})
    ON CONFLICT (col1) DO UPDATE 
    SET (col2, col3) = (EXCLUDED.col2, EXCLUDED.col3)"""

यहाँ एक सरल परीक्षण है:

drop table if exists test_70066823 cascade;
create table test_70066823 (
    id integer primary key, 
    text_column_1 text, 
    text_column_2 text);
insert into test_70066823 select 1,'first','first';
insert into test_70066823 select 2,'second','second';
select * from test_70066823;
-- id | text_column_1 | text_column_2
------+---------------+---------------
--  1 | first         | first
--  2 | second        | second
--(2 rows)


insert into test_70066823
values
        (1, 'third','first'),
        (3, 'fourth','third'),
        (4, 'fifth','fourth'),
        (2, 'sixth','second')
on conflict (id) do update 
set text_column_1=EXCLUDED.text_column_1,
    text_column_2=EXCLUDED.text_column_2;

select * from test_70066823;
-- id | text_column_1 | text_column_2
------+---------------+---------------
--  1 | third         | first
--  3 | fourth        | third
--  4 | fifth         | fourth
--  2 | sixth         | second
--(4 rows)

बेहतर इंसर्ट प्रदर्शन के लिए आप इसे देख सकते हैं। एक साधारण स्ट्रिंग-आधारित execute या execute_many के साथ सम्मिलन वहां उल्लिखित शीर्ष 2 सबसे धीमे दृष्टिकोण हैं।

1
Zegarek 22 नवम्बर 2021, 18:24