समस्या
मैनुअल बताता है:
<ब्लॉककोट>
वैकल्पिक RETURNING
खंड UPDATE
का कारण बनता है वास्तव में अद्यतन की गई प्रत्येक पंक्ति के आधार पर गणना और वापसी मूल्य। FROM
. में उल्लिखित तालिका के स्तंभों और/या अन्य तालिकाओं के स्तंभों का उपयोग करने वाला कोई व्यंजक , गणना की जा सकती है। तालिका के कॉलम के नए (अपडेट के बाद) मानों का उपयोग किया जाता है . RETURNING
. का सिंटैक्स सूची SELECT
. की आउटपुट सूची के समान है ।
बोल्ड जोर मेरा। RETURNING
. में पुरानी पंक्ति तक पहुंचने का कोई तरीका नहीं है खंड। आप इस प्रतिबंध के आसपास एक ट्रिगर या एक अलग SELECT
. के साथ काम कर सकते हैं पहले UPDATE
जैसा कि टिप्पणी की गई थी, लेन-देन में लिपटा हुआ या CTE में लिपटा हुआ था।
हालांकि, आप जो हासिल करने की कोशिश कर रहे हैं वह बिल्कुल ठीक काम करता है यदि आप FROM
. में तालिका के किसी अन्य उदाहरण में शामिल होते हैं खंड:
समवर्ती लेखन के बिना समाधान
UPDATE tbl x
SET tbl_id = 23
, name = 'New Guy'
FROM tbl y -- using the FROM clause
WHERE x.tbl_id = y.tbl_id -- must be UNIQUE NOT NULL
AND x.tbl_id = 3
RETURNING y.tbl_id AS old_id, y.name AS old_name
, x.tbl_id , x.name;
रिटर्न:
old_id | old_name | tbl_id | name
--------+----------+--------+---------
3 | Old Guy | 23 | New Guy
स्व-जुड़ने के लिए उपयोग किया जाने वाला कॉलम UNIQUE NOT NULL
. होना चाहिए . सरल उदाहरण में, WHERE
शर्त एक ही कॉलम पर है tbl_id
, लेकिन यह सिर्फ संयोग है। किसी भी . के लिए काम करता है शर्तें।
मैंने इसका परीक्षण 8.4 से 13 तक PostgreSQL संस्करणों के साथ किया।
यह INSERT
. के लिए अलग है :
- इसमें सम्मिलित करें ... चयन से ... रिटर्निंग आईडी मैपिंग
समवर्ती लेखन भार वाले समाधान
एक ही पंक्तियों पर समवर्ती लेखन संचालन के साथ दौड़ की स्थिति से बचने के कई तरीके हैं। (ध्यान दें कि असंबंधित पंक्तियों पर समवर्ती लेखन संचालन कोई समस्या नहीं है।) सरल, धीमी और सुनिश्चित (लेकिन महंगी) विधि SERIALIZABLE
के साथ लेन-देन को चलाने के लिए है अलगाव स्तर:
BEGIN ISOLATION LEVEL SERIALIZABLE;
UPDATE ... ;
COMMIT;
लेकिन यह शायद अधिक है। और आपको क्रमांकन विफल होने की स्थिति में ऑपरेशन को दोहराने के लिए तैयार रहने की आवश्यकता है।
सरल और तेज़ (और समवर्ती लेखन भार के साथ उतना ही विश्वसनीय) एक . पर एक स्पष्ट लॉक है अद्यतन की जाने वाली पंक्ति:
UPDATE tbl x
SET tbl_id = 24
, name = 'New Gal'
FROM (SELECT tbl_id, name FROM tbl WHERE tbl_id = 4 FOR UPDATE) y
WHERE x.tbl_id = y.tbl_id
RETURNING y.tbl_id AS old_id, y.name AS old_name
, x.tbl_id , x.name;
ध्यान दें कि कैसे WHERE
शर्त को सबक्वेरी में ले जाया गया (फिर से, कुछ भी हो सकता है ), और केवल सेल्फ-जॉइन (UNIQUE NOT NULL
. पर) कॉलम (एस)) बाहरी क्वेरी में रहता है। यह गारंटी देता है कि केवल पंक्तियों को आंतरिक SELECT
. द्वारा लॉक किया गया है संसाधित होते हैं। WHERE
स्थितियाँ एक क्षण बाद पंक्तियों के किसी भिन्न समूह में हल हो सकती हैं।
देखें:
- परमाणु अद्यतन .. पोस्टग्रेज में चुनें
db<>यहां बेला करें
पुराना sqlfiddle