9.5 और नए:
PostgreSQL 9.5 और नए समर्थन INSERT ... ON CONFLICT (key) DO UPDATE
(और ON CONFLICT (key) DO NOTHING
), यानी अपरर्ट।
ON DUPLICATE KEY UPDATE
।
त्वरित स्पष्टीकरण।
उपयोग के लिए मैनुअल देखें - विशेष रूप से conflict_action वाक्य रचना आरेख में खंड, और व्याख्यात्मक पाठ।
नीचे दिए गए 9.4 और पुराने समाधानों के विपरीत, यह सुविधा कई परस्पर विरोधी पंक्तियों के साथ काम करती है और इसके लिए विशेष लॉकिंग या पुन:प्रयास लूप की आवश्यकता नहीं होती है।
सुविधा जोड़ने की प्रतिबद्धता यहाँ है और इसके विकास के बारे में चर्चा यहाँ है।
यदि आप 9.5 पर हैं और आपको पिछड़े-संगत होने की आवश्यकता नहीं है, तो आप अभी पढ़ना बंद कर सकते हैं ।
9.4 और पुराने:
PostgreSQL में कोई अंतर्निहित UPSERT
नहीं है (या MERGE
) सुविधा, और समवर्ती उपयोग की स्थिति में इसे कुशलतापूर्वक करना बहुत कठिन है।
यह लेख समस्या पर उपयोगी विस्तार से चर्चा करता है।
सामान्य तौर पर आपको दो विकल्पों में से चुनना होगा:
- पुन:प्रयास लूप में व्यक्तिगत सम्मिलित/अद्यतन संचालन; या
- टेबल लॉक करना और बैच मर्ज करना
व्यक्तिगत पंक्ति पुन:प्रयास लूप
यदि आप एक साथ कई कनेक्शन सम्मिलित करने का प्रयास करना चाहते हैं तो पुन:प्रयास लूप में अलग-अलग पंक्ति अप्सर्ट का उपयोग करना उचित विकल्प है।
PostgreSQL दस्तावेज़ में एक उपयोगी प्रक्रिया है जो आपको डेटाबेस के अंदर एक लूप में ऐसा करने देगी। यह अधिकांश भोले समाधानों के विपरीत, खोए हुए अपडेट से बचाता है और दौड़ सम्मिलित करता है। यह केवल READ COMMITTED
. में काम करेगा मोड और केवल तभी सुरक्षित है जब लेन-देन में आप केवल यही करते हैं। यदि ट्रिगर या द्वितीयक अद्वितीय कुंजियाँ अद्वितीय उल्लंघन का कारण बनती हैं, तो फ़ंक्शन ठीक से काम नहीं करेगा।
यह रणनीति बहुत अक्षम है। जब भी व्यावहारिक हो तो आपको काम के लिए कतार में लगना चाहिए और इसके बजाय नीचे बताए अनुसार एक बल्क अप्सर्ट करना चाहिए।
इस समस्या के समाधान के कई प्रयास रोलबैक पर विचार करने में विफल होते हैं, इसलिए उनके परिणामस्वरूप अपूर्ण अद्यतन होते हैं। दो लेन-देन एक दूसरे के साथ दौड़; उनमें से एक सफलतापूर्वक INSERT
एस; दूसरे को डुप्लीकेट कुंजी त्रुटि मिलती है और एक UPDATE
करता है बजाय। UPDATE
INSERT
. की प्रतीक्षा में ब्लॉक रोलबैक या प्रतिबद्ध करने के लिए। जब यह वापस आ जाता है, तो UPDATE
कंडीशन री-चेक शून्य पंक्तियों से मेल खाता है, भले ही UPDATE
कमिट करता है कि उसने वास्तव में आपके द्वारा अपेक्षित अपरर्ट नहीं किया है। आपको परिणाम पंक्ति गणना की जांच करनी होगी और जहां आवश्यक हो वहां पुनः प्रयास करना होगा।
कुछ प्रयास किए गए समाधान भी चयन दौड़ पर विचार करने में विफल होते हैं। यदि आप स्पष्ट और सरल प्रयास करते हैं:
-- THIS IS WRONG. DO NOT COPY IT. It's an EXAMPLE.
BEGIN;
UPDATE testtable
SET somedata = 'blah'
WHERE id = 2;
-- Remember, this is WRONG. Do NOT COPY IT.
INSERT INTO testtable (id, somedata)
SELECT 2, 'blah'
WHERE NOT EXISTS (SELECT 1 FROM testtable WHERE testtable.id = 2);
COMMIT;
फिर जब दो एक साथ चलते हैं तो कई विफलता मोड होते हैं। एक अद्यतन पुन:जांच के साथ पहले से ही चर्चा की गई समस्या है। दूसरा वह स्थान है जहां दोनों UPDATE
उसी समय, शून्य पंक्तियों का मिलान करना और जारी रखना। फिर वे दोनों EXISTS
करते हैं परीक्षण, जो पहले . होता है INSERT
. दोनों को शून्य पंक्तियाँ मिलती हैं, इसलिए दोनों INSERT
करते हैं . डुप्लीकेट कुंजी त्रुटि के साथ एक विफल हो जाता है।
यही कारण है कि आपको पुन:प्रयास लूप की आवश्यकता है। आप सोच सकते हैं कि आप चतुर SQL के साथ डुप्लिकेट कुंजी त्रुटियों या खोए हुए अपडेट को रोक सकते हैं, लेकिन आप ऐसा नहीं कर सकते। आपको पंक्तियों की संख्या की जांच करने या डुप्लीकेट कुंजी त्रुटियों (चुने हुए दृष्टिकोण के आधार पर) को संभालने और पुनः प्रयास करने की आवश्यकता है।
कृपया इसके लिए अपना स्वयं का समाधान न करें। संदेश कतारबद्ध होने की तरह, यह शायद गलत है।
लॉक के साथ बल्क अपरर्ट
कभी-कभी आप बल्क अप्सर्ट करना चाहते हैं, जहां आपके पास एक नया डेटा सेट होता है जिसे आप पुराने मौजूदा डेटा सेट में मर्ज करना चाहते हैं। यह विशाल है व्यक्तिगत पंक्ति अप्सर्ट की तुलना में अधिक कुशल और व्यावहारिक होने पर इसे प्राथमिकता दी जानी चाहिए।
इस मामले में, आप आमतौर पर निम्नलिखित प्रक्रिया का पालन करते हैं:
-
CREATE
एकTEMPORARY
टेबल -
COPY
या अस्थायी तालिका में नया डेटा बल्क-सम्मिलित करें -
LOCK
लक्ष्य तालिकाIN EXCLUSIVE MODE
. यह अन्य लेन-देन कोSELECT
. की अनुमति देता है , लेकिन तालिका में कोई परिवर्तन न करें। -
एक
UPDATE ... FROM
. करें अस्थायी तालिका में मानों का उपयोग करते हुए मौजूदा अभिलेखों का; -
एक
INSERT
करें उन पंक्तियों की संख्या जो लक्ष्य तालिका में पहले से मौजूद नहीं हैं; -
COMMIT
, ताला मुक्त करना।
उदाहरण के लिए, प्रश्न में दिए गए उदाहरण के लिए, बहु-मूल्यवान INSERT
. का उपयोग करके अस्थायी तालिका को भरने के लिए:
BEGIN;
CREATE TEMPORARY TABLE newvals(id integer, somedata text);
INSERT INTO newvals(id, somedata) VALUES (2, 'Joe'), (3, 'Alan');
LOCK TABLE testtable IN EXCLUSIVE MODE;
UPDATE testtable
SET somedata = newvals.somedata
FROM newvals
WHERE newvals.id = testtable.id;
INSERT INTO testtable
SELECT newvals.id, newvals.somedata
FROM newvals
LEFT OUTER JOIN testtable ON (testtable.id = newvals.id)
WHERE testtable.id IS NULL;
COMMIT;
संबंधित पठन
- यूपीएसईआरटी विकी पेज
- पोस्टग्रेज में यूपीएसईआरटीवाद
- पोस्टग्रेएसक्यूएल में डुप्लीकेट अपडेट पर डालें?
- http://petereisentraut.blogspot.com/2010/05/merge-syntax.html
- लेन-देन के बारे में बताएं
- क्या किसी ऐसे फ़ंक्शन में SELECT या INSERT है जो दौड़ की स्थिति से ग्रस्त है?
- एसक्यूएल
MERGE
PostgreSQL विकी पर - आजकल Postgresql में UPSERT को लागू करने का सबसे मुहावरेदार तरीका
MERGE
के बारे में क्या? ?
SQL-मानक MERGE
वास्तव में खराब परिभाषित संगामिति शब्दार्थ है और पहले एक तालिका को लॉक किए बिना ऊपर करने के लिए उपयुक्त नहीं है।
यह डेटा विलय के लिए वास्तव में उपयोगी OLAP कथन है, लेकिन यह वास्तव में समवर्ती-सुरक्षित अप्सर्ट के लिए उपयोगी समाधान नहीं है। अन्य DBMSes का उपयोग करने वाले लोगों को MERGE
. का उपयोग करने के लिए बहुत सी सलाह है अप्सर्ट के लिए, लेकिन यह वास्तव में गलत है।
अन्य डीबी:
INSERT ... ON DUPLICATE KEY UPDATE
MySQL मेंMERGE
MS SQL सर्वर से (लेकिन ऊपरMERGE
के बारे में देखें) समस्याएं)MERGE
Oracle से (लेकिन ऊपरMERGE
के बारे में देखें) समस्याएं)