PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

INSERT से RETURNING ... ON CONFLICT . में बहिष्कृत पंक्तियों को कैसे शामिल करें

आपको मिली त्रुटि:

<ब्लॉकक्वॉट>

संघर्ष पर अद्यतन करें आदेश दूसरी बार पंक्ति को प्रभावित नहीं कर सकता

इंगित करता है कि आप एक ही पंक्ति में एक ही पंक्ति को एक से अधिक बार ऊपर करने का प्रयास कर रहे हैं। दूसरे शब्दों में:आपके पास (name, url, email) . पर डुप्लीकेट हैं आपके VALUES . में सूची। डुप्लिकेट को मोड़ो (यदि वह एक विकल्प है) और इसे काम करना चाहिए। लेकिन आपको यह तय करना होगा कि डुप्ली के प्रत्येक सेट में से कौन सी पंक्ति चुननी है।

INSERT INTO feeds_person (created, modified, name, url, email)
SELECT DISTINCT ON (name, url, email) *
FROM  (
   VALUES
   ('blah', 'blah', 'blah', 'blah', 'blah')
   -- ... more
   ) v(created, modified, name, url, email)  -- match column list
ON     CONFLICT (name, url, email) DO UPDATE
SET    url = feeds_person.url
RETURNING id;

चूंकि हम एक फ्री-स्टैंडिंग VALUES . का उपयोग करते हैं अभिव्यक्ति अब, आपको गैर-डिफ़ॉल्ट प्रकारों के लिए स्पष्ट प्रकार के कास्ट जोड़ना होगा। पसंद:

VALUES
    (timestamptz '2016-03-12 02:47:56+01'
   , timestamptz '2016-03-12 02:47:56+01'
   , 'n3', 'u3', 'e3')
   ...

आपका timestamptz कॉलम को एक स्पष्ट प्रकार की कास्ट की आवश्यकता होती है, जबकि स्ट्रिंग प्रकार डिफ़ॉल्ट text . के साथ काम कर सकते हैं . (आप अभी भी varchar(n) . पर कास्ट कर सकते हैं तुरंत।)

यह निर्धारित करने के तरीके हैं कि प्रत्येक डुप्लीकेट सेट से कौन सी पंक्ति चुननी है:

  • समूह द्वारा प्रत्येक समूह में पहली पंक्ति का चयन करें?

आप सही कह रहे हैं, बहिष्कृत . होने का कोई तरीका नहीं है (वर्तमान में) RETURNING . में पंक्तियाँ खंड। मैं पोस्टग्रेज विकी को उद्धृत करता हूं:

<ब्लॉकक्वॉट>

ध्यान दें कि RETURNING "EXCLUDED.* . दिखाई नहीं देता "उपनाम UPDATE से (सिर्फ सामान्य "TARGET.* " उपनाम वहां दिखाई दे रहा है। ऐसा करने से साधारण, सामान्य मामलों के लिए कष्टप्रद अस्पष्टता पैदा करने के लिए सोचा जाता है [30] कम या बिना किसी लाभ के। भविष्य में किसी बिंदु पर, हम उजागर करने का एक तरीका अपना सकते हैं अगरRETURNING -प्रोजेक्टेड टुपल्स को डाला और अपडेट किया गया था, लेकिन शायद इसे फीचर [31] के पहले प्रतिबद्ध पुनरावृत्ति में शामिल करने की आवश्यकता नहीं है।

हालांकि , आपको उन पंक्तियों को अपडेट नहीं करना चाहिए जिन्हें अपडेट नहीं किया जाना चाहिए। खाली अपडेट लगभग नियमित अपडेट जितना ही महंगा होता है - और इसके अनपेक्षित दुष्प्रभाव हो सकते हैं। शुरू करने के लिए आपको यूपीएसईआरटी की सख्ती से आवश्यकता नहीं है, आपका मामला "चयन या सम्मिलित करें" जैसा दिखता है। संबंधित:

  • क्या किसी ऐसे फ़ंक्शन में SELECT या INSERT है जो दौड़ की स्थिति से ग्रस्त है?

एक पंक्तियों का एक सेट डालने का साफ तरीका डेटा-संशोधित सीटीई के साथ होगा:

WITH val AS (
   SELECT DISTINCT ON (name, url, email) *
   FROM  (
      VALUES 
      (timestamptz '2016-1-1 0:0+1', timestamptz '2016-1-1 0:0+1', 'n', 'u', 'e')
    , ('2016-03-12 02:47:56+01', '2016-03-12 02:47:56+01', 'n1', 'u3', 'e3')
      -- more (type cast only needed in 1st row)
      ) v(created, modified, name, url, email)
   )
, ins AS (
   INSERT INTO feeds_person (created, modified, name, url, email)
   SELECT created, modified, name, url, email FROM val
   ON     CONFLICT (name, url, email) DO NOTHING
   RETURNING id, name, url, email
   )
SELECT 'inserted' AS how, id FROM ins  -- inserted
UNION  ALL
SELECT 'selected' AS how, f.id         -- not inserted
FROM   val v
JOIN   feeds_person f USING (name, url, email);

अतिरिक्त जटिलता को बड़ी तालिकाओं के लिए भुगतान करना चाहिए जहां INSERT नियम है और SELECT अपवाद।

मूल रूप से, मैंने एक NOT EXISTS added जोड़ा था अंतिम SELECT . पर विधेय परिणाम में डुप्लिकेट को रोकने के लिए। लेकिन यह बेमानी थी। एक ही क्वेरी के सभी सीटीई टेबल के समान स्नैपशॉट देखते हैं। सेट ON CONFLICT (name, url, email) DO NOTHING के साथ लौटा INNER JOIN . के बाद लौटाए गए सेट के लिए परस्पर अनन्य है एक ही कॉलम पर।

दुर्भाग्य से यह एक दौड़ की स्थिति के लिए छोटी विंडो भी खोलता है . अगर...

  • एक समवर्ती लेन-देन परस्पर विरोधी पंक्तियों को सम्मिलित करता है
  • अभी तक प्रतिबद्ध नहीं है
  • लेकिन अंततः प्रतिबद्ध होता है

... कुछ पंक्तियाँ खो सकती हैं।

आप बस INSERT .. ON CONFLICT DO NOTHING , उसके बाद एक अलग SELECT सभी पंक्तियों के लिए क्वेरी - इसे दूर करने के लिए एक ही लेनदेन के भीतर। जो बदले में एक और दौड़ की स्थिति के लिए छोटी विंडो opens खोलता है यदि समवर्ती लेनदेन INSERT . के बीच तालिका में लिखने के लिए प्रतिबद्ध हो सकते हैं और SELECT (डिफ़ॉल्ट रूप से READ COMMITTED अलगाव स्तर)। REPEATABLE READ से बचा जा सकता है लेनदेन अलगाव (या सख्त)। या (संभवतः महंगा या अस्वीकार्य भी) पूरी मेज पर ताला लिखें। आपको अपनी जरूरत का कोई भी व्यवहार मिल सकता है, लेकिन इसकी कीमत चुकानी पड़ सकती है।

संबंधित:

  • PostgreSQL में ON CONFLICT के साथ RETURNING का उपयोग कैसे करें?
  • अपडेट करने की आवश्यकता के बिना INSERT से ON CONFLICT के साथ वापसी पंक्तियाँ



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. रेल:पीजी रत्न स्थापित करने में त्रुटि

  2. क्या PostgreSQL में सरणी तत्वों पर एक विशिष्टता बाधा हो सकती है?

  3. PostgreSQL 12 प्रतिकृति और विफलता को repmgr के साथ स्वचालित कैसे करें - भाग 2

  4. चयन पीएल/पीजीएसक्यूएल फ़ंक्शन में अपवाद उठाता है

  5. PostgreSQL में 2 तिथियों के बीच कार्य घंटों की गणना करें