यह एक कार्यान्वयन निर्णय है। यह Postgres प्रलेखन, WITH
क्वेरीज़ (सामान्य तालिका अभिव्यक्तियाँ) में वर्णित है । मुद्दे से संबंधित दो पैराग्राफ हैं।
सबसे पहले, मनाया व्यवहार का कारण:
उप-कथनोंWITH
को एक दूसरे के साथ और मुख्य क्वेरी के साथ समवर्ती रूप से निष्पादित किया जाता है । इसलिए, डेटा-संशोधित करने वाले कथनों का उपयोग करते समय WITH
, जिस क्रम में निर्दिष्ट अद्यतन वास्तव में होता है वह अप्रत्याशित है। सभी बयानों को एक ही स्नैपशॉट के साथ निष्पादित किया जाता है (अध्याय 13 देखें), इसलिए वे लक्ष्य तालिकाओं पर एक दूसरे के प्रभाव को "नहीं" देख सकते हैं। यह पंक्ति अद्यतनों के वास्तविक क्रम की अप्रत्याशितता के प्रभावों को कम करता है, और इसका अर्थ है कि RETURNING
डेटा विभिन्न WITH
उप-कथनों और मुख्य क्वेरी के बीच परिवर्तनों को संप्रेषित करने का एकमात्र तरीका है । इसका एक उदाहरण यह है कि ...
मैंने pgsql-docs के साथ एक सुझाव पोस्ट करने के बाद , मार्को टिक्काजा ने समझाया (जो इरविन के जवाब से सहमत है):
इन्सर्ट-अपडेट और इंसर्ट-डिलीट केस काम नहीं करते क्योंकि UPDATEs और DELETEs के पास INSERTed पंक्तियों को देखने का कोई तरीका नहीं है क्योंकि उनके स्नैपशॉट को INSERT होने से पहले लिया गया है। इन दोनों मामलों के बारे में कुछ भी अप्रत्याशित नहीं है।
इसलिए आपके कथन को अपडेट नहीं करने का कारण ऊपर दिए गए पहले पैराग्राफ ("स्नैपशॉट्स") के द्वारा समझाया जा सकता है। जब आप सीटीई को संशोधित करते हैं तो क्या होता है, यह सभी और मुख्य क्वेरी निष्पादित होती है और डेटा (तालिकाओं) के समान स्नैपशॉट को "देखते हैं", क्योंकि वे स्टेटमेंट निष्पादन से पहले थे। सीटीई RETURNING
क्लाज का उपयोग करके एक दूसरे को और मुख्य क्वेरी के लिए उन्होंने क्या डाला / अपडेट / डिलीट किया है, इसके बारे में जानकारी पास कर सकते हैं, लेकिन वे सीधे तालिकाओं में परिवर्तन नहीं देख सकते हैं। तो देखते हैं कि आपके कथन में क्या होता है:
WITH newval AS (
INSERT INTO tbl(val) VALUES (1) RETURNING id
) UPDATE tbl SET val=2 FROM newval WHERE tbl.id=newval.id;
हमारे पास 2 भाग हैं, CTE ( newval
):
-- newval
INSERT INTO tbl(val) VALUES (1) RETURNING id
और मुख्य प्रश्न:
-- main
UPDATE tbl SET val=2 FROM newval WHERE tbl.id=newval.id
निष्पादन का प्रवाह कुछ इस प्रकार है:
initial data: tbl
id │ val
(empty)
/ \
/ \
/ \
newval: \
tbl (after newval) \
id │ val \
1 │ 1 |
|
newval: returns |
id |
1 |
\ |
\ |
\ |
main query
नतीजतन, जब मुख्य क्वेरी तालिका के tbl
साथ (स्नैपशॉट में देखी गई) में newval
मिलती है, तो यह 1-पंक्ति तालिका के साथ एक खाली तालिका में मिलती है। जाहिर है कि यह 0 पंक्तियों को अद्यतन करता है। इसलिए बयान कभी भी नई सम्मिलित पंक्ति को संशोधित करने के लिए नहीं आया और यही आप देखते हैं।
आपके मामले में समाधान, या तो पहले से सही मान सम्मिलित करने के लिए कथन को फिर से लिखना है या 2 कथन का उपयोग करना है। एक वो जो इन्सर्ट करता है और दूसरा अपडेट करने के लिए।
इसी तरह की अन्य स्थितियां भी हैं, जैसे कि यदि कथन एक था INSERT
और फिर DELETE
उसी पंक्तियों पर। यह ठीक उसी कारणों से विफल हो जाएगा।
कुछ अन्य मामले, अपडेट-अपडेट और अपडेट-डिलीट के साथ और उनके व्यवहार को एक ही डॉक्स पृष्ठ में, निम्नलिखित पैराग्राफ में समझाया गया है।
एक ही कथन में एक ही पंक्ति को दो बार अपडेट करने की कोशिश समर्थित नहीं है। केवल संशोधनों में से एक होता है, लेकिन यह विश्वास करना आसान नहीं है (और कभी-कभी संभव नहीं है) जो एक की भविष्यवाणी करने के लिए है। यह एक पंक्ति को हटाने के लिए भी लागू होता है जो पहले से ही एक ही बयान में अपडेट किया गया था: केवल अपडेट किया जाता है। इसलिए आपको आम तौर पर एक बयान में एक पंक्ति को दो बार संशोधित करने की कोशिश से बचना चाहिए। विशेष रूप से उप-बयानों के साथ लिखने से बचें जो मुख्य बयान या एक सह-उप-बयान द्वारा परिवर्तित समान पंक्तियों को प्रभावित कर सकते हैं। इस तरह के बयान का प्रभाव अनुमानित नहीं होगा।
और मार्को तिइकजा के जवाब में:
अद्यतन अद्यतन और अद्यतन हटाना रद्द करें मामलों स्पष्ट रूप से कर रहे हैं नहीं एक ही अंतर्निहित कार्यान्वयन विस्तार (डालने अद्यतन और डालने हटाना रद्द मामलों के रूप में) की वजह से।
अपडेट-अपडेट का मामला काम नहीं करता क्योंकि यह आंतरिक रूप से हैलोवीन समस्या की तरह दिखता है, और पोस्टग्रेज के पास यह जानने का कोई तरीका नहीं है कि कौन सी ट्यूपल्स को दो बार अपडेट करना ठीक होगा और कौन से लोग हैलोवीन समस्या को फिर से प्रस्तुत कर सकते हैं।
तो इसका कारण एक ही है (CTE को संशोधित कैसे किया जाता है और प्रत्येक CTE एक ही स्नैपशॉट को कैसे देखता है) लेकिन इन 2 मामलों में विवरण अलग-अलग हैं, क्योंकि वे अधिक जटिल हैं और परिणाम अपडेट-अपडेट के मामले में अप्रत्याशित हो सकते हैं।
सम्मिलित-अद्यतन (आपके मामले के रूप में) और एक समान प्रविष्टि-हटाएँ परिणाम अनुमानित हैं। केवल सम्मिलित होता है क्योंकि दूसरे ऑपरेशन (अपडेट या डिलीट) के पास नई सम्मिलित पंक्तियों को देखने और प्रभावित करने का कोई तरीका नहीं है।
सुझाए गए समाधान हालांकि सभी मामलों के लिए समान हैं जो एक ही पंक्तियों को एक से अधिक बार संशोधित करने का प्रयास करते हैं: ऐसा न करें। या तो ऐसे कथन लिखें जो प्रत्येक पंक्ति को एक बार संशोधित करते हैं या अलग (2 या अधिक) कथनों का उपयोग करते हैं।