एक नमूना तालिका और डेटा
CREATE TABLE dupes(col1 int primary key, col2 int, col3 text,
CONSTRAINT col2_unique UNIQUE (col2)
);
INSERT INTO dupes values(1,1,'a'),(2,2,'b');
समस्या का पुन: प्रस्तुत करना
INSERT INTO dupes values(3,2,'c')
ON CONFLICT (col1) DO UPDATE SET col3 = 'c', col2 = 2
इसको Q1 कहते हैं। परिणाम है
ERROR: duplicate key value violates unique constraint "col2_unique"
DETAIL: Key (col2)=(2) already exists.
विरोध_बनाते हुए अद्वितीय सूचकांक निष्कर्ष निकाल सकते हैं। निष्कर्ष निकालते समय, इसमें एक या एक से अधिक index_column_name कॉलम और / या index_expression अभिव्यक्तियाँ और एक वैकल्पिक index_predicate होता है। सभी तालिका_नाम अद्वितीय अनुक्रमणिकाएँ, जो आदेश के संबंध में, बिल्कुल परस्पर विरोधी_टर्ज-निर्दिष्ट कॉलम / अभिव्यक्तियों को अर्बिटर इंडेक्स के रूप में अनुमानित (चुना हुआ) हैं। यदि एक index_predicate निर्दिष्ट किया जाता है, तो इसे अनुमान के लिए एक और आवश्यकता के रूप में, arbiter indexes को संतुष्ट करना चाहिए।
यह धारणा देता है कि निम्नलिखित क्वेरी को काम करना चाहिए, लेकिन ऐसा नहीं है क्योंकि यह वास्तव में col1 और col2 पर एक साथ अद्वितीय सूचकांक की आवश्यकता होगी। हालाँकि ऐसा कोई इंडेक्स इस बात की गारंटी नहीं देगा कि col1 और col2 व्यक्तिगत रूप से अद्वितीय होंगे जो ओपी की आवश्यकताओं में से एक है।
INSERT INTO dupes values(3,2,'c')
ON CONFLICT (col1,col2) DO UPDATE SET col3 = 'c', col2 = 2
चलिए इस प्रश्न को Q2 कहते हैं (यह सिंटैक्स त्रुटि के साथ विफल होता है)
क्यों?
Postgresql इस तरह से व्यवहार करता है, क्योंकि जब दूसरे स्तंभ पर कोई विरोध होता है, तो उसे अच्छी तरह से परिभाषित नहीं किया जाना चाहिए। संभावनाओं की संख्या है। उपरोक्त Q1 प्रश्न में उदाहरण के लिए, col1
जब कोई विरोध हो , तो क्या अपडेट को स्थगित कर देना चाहिए col2
? लेकिन क्या होगा अगर उस पर एक और संघर्ष होता है col1
? कैसे postgresql को संभालने की उम्मीद है?
एक तरकीब
एक समाधान पुराने फैशन UPSERT के साथ CONFLICT को जोड़ना है ।
CREATE OR REPLACE FUNCTION merge_db(key1 INT, key2 INT, data TEXT) RETURNS VOID AS
$$
BEGIN
LOOP
UPDATE dupes SET col3 = data WHERE col1 = key1 and col2 = key2;
IF found THEN
RETURN;
END IF;
BEGIN
INSERT INTO dupes VALUES (key1, key2, data) ON CONFLICT (col1) DO UPDATE SET col3 = data;
RETURN;
EXCEPTION WHEN unique_violation THEN
BEGIN
INSERT INTO dupes VALUES (key1, key2, data) ON CONFLICT (col2) DO UPDATE SET col3 = data;
RETURN;
EXCEPTION WHEN unique_violation THEN
END;
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
आपको इस संग्रहित फ़ंक्शन के तर्क को संशोधित करने की आवश्यकता होगी ताकि यह कॉलम को उसी तरह अपडेट करे जिस तरह से आप इसे चाहते हैं। इसे ऐसे ही इन्वॉल्व करें
SELECT merge_db(3,2,'c');
SELECT merge_db(1,2,'d');