sql - पीएल/पीजीएसक्यूएल में एसक्यूएल स्टेटमेंट चलाएं, अगर कोई पंक्ति मौजूद न हो




postgresql stored-procedures (3)

पोस्टग्रेस में returning खंड और सीटीई हैं जो आप चाहते हैं:

WITH t1 as (
      INSERT INTO table1 (id, value)
          VALUES (1, 'a')
          ON CONFLICT DO NOTHING
          RETURNING *
     ),
     t2 as (
      INSERT INTO table2 (table1_id, value) 
          SELECT id, value 
          FROM (SELECT 1 as id, 'a' as value) t
          WHERE NOT EXISTS (SELECT 1 FROM t1) 
   )
UPDATE table3
    set (table1_id, time) = (1, now())
    WHERE NOT EXISTS (SELECT 1 FROM t1);

update अजीब लग रहा है क्योंकि यह table3 में सभी पंक्तियों को अपडेट करता है।

मैं पोस्टग्रेस 9.6 में पीएल / पीजीएस्यूएल फ़ंक्शन में ऐसा कुछ करना चाहता हूं:

INSERT INTO table1 (id, value) VALUES (1, 'a') ON CONFLICT DO NOTHING;
--- If the above statement didn't insert a new row
---   because id of 1 already existed, 
---   then run the following statements

INSERT INTO table2 (table1_id, value) VALUES (1, 'a');
UPDATE table3 set (table1_id, time) = (1, now());

हालांकि, मुझे नहीं पता कि यह कैसे तय किया जाए कि पहले INSERT वास्तव में एक नई पंक्ति डाली, या क्या ON CONFLICT DO NOTHING किया गया था।

मैं फ़ंक्शन की शुरुआत में एक SELECT कर सकता हूं यह देखने के लिए कि क्या 1 के id के साथ एक रिकार्ड table1 1 में मौजूद है, यह सभी एसक्यूएल स्टेटमेंट चलाने से पहले है, लेकिन इससे मुझे दौड़ की स्थितियों का table1 करना पड़ेगा।


शायद आप ऐसा कुछ मतलब है?

INSERT INTO table1 (id, value) VALUES (1, 'a') ON CONFLICT DO NOTHING;
--- If the above statement didn't insert a new row
---   because id of 1 already existed, 
---   then run the following statements

affected_rows := SQL%ROWCOUNT;

IF affected_rows = 0 THEN
    INSERT INTO table2 (table1_id, value) VALUES (1, 'a');
    UPDATE table3 set (table1_id, time) = (1, now());
END IF

एक plpgsql फ़ंक्शन के लिए, विशेष चर का उपयोग करें:

CREATE FUNCTION foo(int, text)
 RETURNS void AS
$$
BEGIN
   INSERT INTO table1 (id, value) VALUES ($1, $2) ON CONFLICT DO NOTHING;

   IF NOT FOUND THEN
      INSERT INTO table2 (table1_id, value) VALUES ($1, $2);
      UPDATE table3 set (table1_id, time) = ($1, now())
      WHERE  ????;  -- you surely don't want to update all rows in table3
   END IF;
END
$$

कॉल करें:

SELECT foo(1, 'a');

INSERT वास्तव में किसी भी पंक्तियों को सम्मिलित नहीं करता है तो INSERT गलत पर सेट है।

ON CONFLICT क्लॉज के बारे में मैनुअल:

किसी ON CONFLICT DO NOTHING इसके वैकल्पिक कार्य के रूप में एक पंक्ति डालने से बचा जाता है।

परिणाम स्थिति प्राप्त करने के बारे में मैनुअल

UPDATE , INSERT , और DELETE स्टेटमेंट सेट करें अगर कम से कम एक पंक्ति प्रभावित होती है, तो झूठी अगर कोई पंक्ति प्रभावित नहीं होती है।

स्पष्ट होने के लिए, यह बाद के बयानों को चलाता है यदि table1 1 में एक पंक्ति मौजूद है, तो नई पंक्ति सम्मिलित नहीं की गई है। (जैसे आपने अनुरोध किया, लेकिन आपके प्रश्न शीर्षक के विपरीत।)

यदि आप केवल एक पंक्ति मौजूद है या नहीं यह जांचना चाहते हैं:

दौड़ की स्थिति?

यदि एक ही लेन-देन में बाद के आदेश table1 (उदाहरण के लिए एक एफके के साथ) में मौजूदा पंक्ति पर निर्भर करते हैं , तो आप उस समय में समवर्ती लेनदेन को हटाने या उसे अपडेट करने के लिए इसे लॉक करना चाहते हैं। ऐसा करने का एक तरीका: DO NOTHING उपयोग करने के बजाय DO UPDATE , लेकिन वास्तव में पंक्ति को अपडेट नहीं करें पंक्ति अब भी बंद है:

INSERT INTO table1 AS t (id, value)
VALUES ($1, $2)
ON     CONFLICT (id) DO UPDATE  -- specify unique column(s) or constraint / index
SET    id = t.id WHERE FALSE;   -- never executed, but locks the row

जाहिर है, यदि आप समवर्ती लेनदेन को रद्द कर सकते हैं जो विवादित तरीके से एक ही पंक्ति को हटा या अपडेट कर सकता है, तो समस्या मौजूद नहीं है।

विस्तृत विवरण:





sql-insert