मुझे दो प्रमुख समस्याएं दिखाई दे रही हैं:
1. आप एक अद्यतन
नहीं डाल सकते हैं एक सबक्वेरी में बिल्कुल . आप इसे डेटा-संशोधित करके हल कर सकते हैं सीटीई
जैसे पैट्रिक प्रदर्शित करता है
, लेकिन यह मामले के लिए आवश्यक से अधिक महंगा और क्रियात्मक है।
2. आपके पास संभावित रूप से खतरनाक नामकरण विरोध . है , जिसे अभी तक संबोधित नहीं किया गया है।
बेहतर क्वेरी / फ़ंक्शन
फिलहाल के लिए SQL फंक्शन रैपर को एक तरफ छोड़ दें (हम उस पर वापस आएंगे)। आप एक साधारण अपडेट
का उपयोग कर सकते हैं एक रिटर्निंग
. के साथ खंड:
UPDATE tbl
SET value1 = 'something_new'
WHERE id = 123
RETURNING row_to_json(ROW(value1, value2));
रिटर्निंग
खंड अद्यतन पंक्ति के स्तंभों को शामिल करते हुए मनमाना अभिव्यक्तियों की अनुमति देता है। यह डेटा-संशोधित सीटीई से छोटा और सस्ता है।
शेष समस्या:पंक्ति निर्माता ROW(...)
कॉलम नामों को संरक्षित नहीं करता है (जो एक ज्ञात कमजोरी है), इसलिए आपको अपने JSON मान में सामान्य कुंजियाँ मिलती हैं:
row_to_json
{"f1":"something_new","f2":"what ever is in value2"}
Postgres 9.3 में आपको पहले चरण या कास्ट को एक अच्छी तरह से परिभाषित पंक्ति प्रकार में समाहित करने के लिए एक CTE अन्य फ़ंक्शन की आवश्यकता होगी। विवरण:
पोस्टग्रेज में 9.4 बस <का उपयोग करें कोड>json_build_object () या json_object()
:
UPDATE tbl
SET value1 = 'something_new'
WHERE id = 123
RETURNING json_build_object('value1', value1, 'value2', value2);
या:
...
RETURNING json_object('{value1, value2}', ARRAY[value1, value2]);
अब आपको मूल कॉलम नाम मिलते हैं या जो भी आपने मुख्य नामों के रूप में चुना है:
row_to_json
{"value1":"something_new","value2":"what ever is in value2"}
इसे एक फ़ंक्शन में लपेटना आसान है, जो हमें आपकी दूसरी समस्या में लाता है ...
नामकरण विरोध
अपने मूल फ़ंक्शन में आप फ़ंक्शन पैरामीटर और कॉलम नामों के लिए समान नामों का उपयोग करते हैं। यह आम तौर पर एक बहुत बुरा विचार . है . आपको यह अच्छी तरह से समझना होगा कि कौन सा पहचानकर्ता किस दायरे में सबसे पहले आता है।
मामले में परिणाम बिलकुल बकवास है:
Create Or Replace Function ExampleTable_Update (id bigint, value1 text) Returns
...
Update ExampleTable
Set Value1 = value1
Where id = id
Returning Value1, Value2;
...
$$ Language SQL;
जबकि आप उम्मीद करते हैं कि id
. का दूसरा उदाहरण फ़ंक्शन पैरामीटर का संदर्भ देगा, ऐसा नहीं है। कॉलम का नाम पहले SQL स्टेटमेंट के दायरे में आता है, दूसरा इंस्टेंस कॉलम को संदर्भित करता है। जिसके परिणामस्वरूप एक ऐसा व्यंजक होता है जो हमेशा सत्य
होता है id
. में NULL मानों को छोड़कर . नतीजतन, आप सभी पंक्तियों को अपडेट करेंगे , जिससे डेटा की विनाशकारी हानि हो सकती है .क्या बुरा है, हो सकता है कि आपको बाद में इसका एहसास भी न हो, क्योंकि SQL फ़ंक्शन एक लौटाएगा रिटर्निंग
. द्वारा परिभाषित मनमानी पंक्ति फ़ंक्शन का क्लॉज (एक लौटाता है) पंक्ति, पंक्तियों का समूह नहीं)।
<उप>इस विशेष मामले में, आपको "भाग्यशाली" मिलेगा, क्योंकि आपके पास value1 =value1
भी है , जो कॉलम को इसके पूर्व-मौजूदा मान के साथ अधिलेखित कर देता है, प्रभावी रूप से .. बहुत महंगे तरीके से कुछ भी नहीं करता है (जब तक कि ट्रिगर कुछ न करें)। आप एक अपरिवर्तित value1
. के साथ एक मनमानी पंक्ति प्राप्त करने के लिए परेशान हो सकते हैं परिणाम के रूप में।उप>
तो, नहीं।
इस तरह के संभावित नामकरण संघर्षों से बचें, जब तक कि आप वास्तव में नहीं जानते कि आप क्या कर रहे हैं (जो स्पष्ट रूप से ऐसा नहीं है)। एक सम्मेलन जो मुझे पसंद है वह है कार्यों में पैरामीटर और चर नामों के लिए एक अंडरस्कोर तैयार करना, जबकि कॉलम नाम कभी भी अंडरस्कोर से शुरू नहीं होते हैं। कई मामलों में आप स्पष्ट होने के लिए केवल स्थितीय संदर्भों का उपयोग कर सकते हैं:$1
, $2
, ..., लेकिन यह केवल आधे मुद्दे को दरकिनार कर देता है। कोई भी तरीका तब तक अच्छा है जब तक आप नामकरण विरोधों से बचें . मेरा सुझाव है:
CREATE OR REPLACE FUNCTION foo (_id bigint, _value1 text)
RETURNS json AS
$func$
UPDATE tbl
SET value1 = _value1
WHERE id = _id
RETURNING json_build_object('value1', value1, 'value2', value2);
$func$ LANGUAGE sql;
यह भी ध्यान रखें कि यह वास्तविक कॉलम मान लौटाता है value1
. में अद्यतन
के बाद , जो आपके इनपुट पैरामीटर के समान हो भी सकता है और नहीं भी हो सकता है _value1
. डेटाबेस नियम या ट्रिगर हस्तक्षेप कर सकते हैं ...