जबकि @ गैरी का उत्तर तकनीकी रूप से सही है, वह यह उल्लेख करने में विफल रहता है कि PostgreSQL करता है इस फ़ॉर्म का समर्थन करें:
UPDATE tbl
SET (col1, col2, ...) = (expression1, expression2, ..)
UPDATE पर मैनुअल पढ़ें एक बार फिर।
गतिशील एसक्यूएल के साथ उसे पूरा करना अभी भी मुश्किल है। चूंकि आपने निर्दिष्ट नहीं किया है, मैं एक साधारण मामला मान रहा हूं जहां विचारों में उनके अंतर्निहित तालिकाओं के समान कॉलम होते हैं।
CREATE VIEW tbl_view AS SELECT * FROM tbl;
समस्याएं
-
विशेष रिकॉर्ड
NEWEXECUTE. के अंदर दिखाई नहीं दे रहा है . मैंNEWपास करता हूंUSING. के साथ एकल पैरामीटर के रूप मेंEXECUTE. का खंड । -
जैसा कि चर्चा की गई है,
UPDATEसूची-रूप के साथ अलग-अलग मानों की आवश्यकता होती है . मैं रिकॉर्ड को अलग-अलग कॉलम में विभाजित करने के लिए उप-चयन का उपयोग करता हूं:UPDATE ... FROM (SELECT ($1).*) x(कोष्ठक
$1. के आसपास है वैकल्पिक नहीं हैं।) यह मुझेstring_agg(). के साथ निर्मित दो कॉलम सूचियों का उपयोग करने की अनुमति देता है कैटलॉग टेबल से:एक के साथ और एक बिना टेबल योग्यता के। -
अलग-अलग स्तंभों के लिए संपूर्ण रूप से एक पंक्ति मान निर्दिष्ट करना संभव नहीं है। मैनुअल:
<ब्लॉककोट>मानक के अनुसार, लक्ष्य स्तंभ नामों की एक कोष्ठक उप-सूची के लिए स्रोत मान कोई भी पंक्ति-मूल्यवान व्यंजक हो सकता है जो स्तंभों की सही संख्या प्रदान करता है। PostgreSQL केवल स्रोत मान को एक पंक्ति निर्माता या उप-
SELECTहोने की अनुमति देता है । -
INSERTसरलता से क्रियान्वित किया जाता है। दृश्य और तालिका की संरचना को समान मानते हुए मैं स्तंभ परिभाषा सूची को छोड़ देता हूं। (सुधार किया जा सकता है, नीचे देखें।)
समाधान
मैंने आपके दृष्टिकोण को चमकदार बनाने के लिए उसमें कई अपडेट किए हैं।
UPDATE के लिए ट्रिगर फ़ंक्शन :
CREATE OR REPLACE FUNCTION f_trg_up()
RETURNS TRIGGER AS
$func$
DECLARE
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(substring(TG_TABLE_NAME from '(.+)_view$'));
cols text;
vals text;
BEGIN
SELECT INTO cols, vals
string_agg(quote_ident(attname), ', ')
,string_agg('x.' || quote_ident(attname), ', ')
FROM pg_attribute
WHERE attrelid = tbl::regclass
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0; -- no system columns
EXECUTE format('
UPDATE %s t
SET (%s) = (%s)
FROM (SELECT ($1).*) x
WHERE t.id = ($2).id'
, tbl, cols, vals) -- assuming unique "id" in every table
USING NEW, OLD;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
INSERT . के लिए ट्रिगर फ़ंक्शन :
CREATE OR REPLACE FUNCTION f_trg_ins()
RETURNS TRIGGER AS
$func$
DECLARE
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(substring(TG_TABLE_NAME from '(.+)_view$'));
BEGIN
EXECUTE 'INSERT INTO ' || tbl || ' SELECT ($1).*'
USING NEW;
RETURN NEW; -- don't return NULL unless you know what you're doing
END
$func$ LANGUAGE plpgsql;
ट्रिगर:
CREATE TRIGGER trg_instead_up
INSTEAD OF UPDATE ON a_view
FOR EACH ROW EXECUTE PROCEDURE f_trg_up();
CREATE TRIGGER trg_instead_ins
INSTEAD OF INSERT ON a_view
FOR EACH ROW EXECUTE PROCEDURE f_trg_ins();
एसक्यूएल फिडल प्रदर्शन INSERT और UPDATE ।
प्रमुख बिंदु
-
तालिका संदर्भ को स्पष्ट बनाने के लिए स्कीमा नाम शामिल करें। एकाधिक स्कीमा में एक ही डेटाबेस में एक ही तालिका नाम के कई उदाहरण हो सकते हैं!
-
क्वेरी
pg_attributeinformation_schema.columns. के बजाय . यह कम पोर्टेबल है, लेकिन काफी तेजी से और मुझे टेबल-ओआईडी का उपयोग करने की अनुमति देता है।- किसी दिए गए स्कीमा में तालिका मौजूद है या नहीं, इसकी जांच कैसे करें
-
तालिका नाम SQLi के विरुद्ध सुरक्षित नहीं हैं जब गतिशील एसक्यूएल के लिए प्रश्नों के निर्माण में स्ट्रिंग के रूप में संभाला जाता है।
quote_ident()के साथ बच जाएं याformat()या वस्तु-पहचानकर्ता प्रकार के साथ। इसमें विशेष ट्रिगर फ़ंक्शन चर शामिल हैंTG_TABLE_SCHEMAऔरTG_TABLE_NAME! -
ऑब्जेक्ट आइडेंटिफ़ायर टाइप करने के लिए कास्ट करें
regclassयह सुनिश्चित करने के लिए कि तालिका का नाम मान्य है और कैटलॉग लुक-अप के लिए OID प्राप्त करें। -
वैकल्पिक रूप से
format(). का उपयोग करें गतिशील क्वेरी स्ट्रिंग को सुरक्षित रूप से बनाने के लिए। -
कैटलॉग टेबल पर पहली क्वेरी के लिए डायनेमिक SQL की कोई आवश्यकता नहीं है। तेज़, आसान।
-
RETURN NEWका उपयोग करें इसके बजायRETURN NULLइन ट्रिगर फ़ंक्शंस में जब तक आप नहीं जानते कि आप क्या कर रहे हैं। (NULLINSERTको रद्द कर देगा वर्तमान पंक्ति के लिए।) -
यह सरल संस्करण मानता है कि प्रत्येक तालिका (और दृश्य) में
id. नामक एक अद्वितीय कॉलम होता है . एक अधिक परिष्कृत संस्करण प्राथमिक कुंजी का गतिशील रूप से उपयोग कर सकता है। -
UPDATEके लिए कार्य दृश्य और तालिका के स्तंभों को किसी भी क्रम में होने देता है , जब तक सेट समान है।INSERT. के लिए फ़ंक्शन दृश्य और तालिका के कॉलम समान क्रम में होने की अपेक्षा करता है . यदि आप मनमानी क्रम की अनुमति देना चाहते हैं, तोINSERT. में एक कॉलम परिभाषा सूची जोड़ें कमांड, ठीक उसी तरह जैसेUPDATE. के साथ । -
अपडेट किए गए संस्करण में
id. में परिवर्तन भी शामिल हैंOLD. का उपयोग करके कॉलम इसके अतिरिक्त।