PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

plpgsql में ट्रिगर फ़ंक्शन में एकाधिक कॉलम अपडेट करें

जबकि @ गैरी का उत्तर तकनीकी रूप से सही है, वह यह उल्लेख करने में विफल रहता है कि PostgreSQL करता है इस फ़ॉर्म का समर्थन करें:

UPDATE tbl
SET (col1, col2, ...) = (expression1, expression2, ..)

UPDATE पर मैनुअल पढ़ें एक बार फिर।

गतिशील एसक्यूएल के साथ उसे पूरा करना अभी भी मुश्किल है। चूंकि आपने निर्दिष्ट नहीं किया है, मैं एक साधारण मामला मान रहा हूं जहां विचारों में उनके अंतर्निहित तालिकाओं के समान कॉलम होते हैं।

CREATE VIEW tbl_view AS SELECT * FROM tbl;

समस्याएं

  • विशेष रिकॉर्ड NEW EXECUTE . के अंदर दिखाई नहीं दे रहा है . मैं 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_attribute information_schema.columns . के बजाय . यह कम पोर्टेबल है, लेकिन काफी तेजी से और मुझे टेबल-ओआईडी का उपयोग करने की अनुमति देता है।

    • किसी दिए गए स्कीमा में तालिका मौजूद है या नहीं, इसकी जांच कैसे करें
  • तालिका नाम SQLi के विरुद्ध सुरक्षित नहीं हैं जब गतिशील एसक्यूएल के लिए प्रश्नों के निर्माण में स्ट्रिंग के रूप में संभाला जाता है। quote_ident() के साथ बच जाएं या format() या वस्तु-पहचानकर्ता प्रकार के साथ। इसमें विशेष ट्रिगर फ़ंक्शन चर शामिल हैं TG_TABLE_SCHEMA और TG_TABLE_NAME !

  • ऑब्जेक्ट आइडेंटिफ़ायर टाइप करने के लिए कास्ट करें regclass यह सुनिश्चित करने के लिए कि तालिका का नाम मान्य है और कैटलॉग लुक-अप के लिए OID प्राप्त करें।

  • वैकल्पिक रूप से format() . का उपयोग करें गतिशील क्वेरी स्ट्रिंग को सुरक्षित रूप से बनाने के लिए।

  • कैटलॉग टेबल पर पहली क्वेरी के लिए डायनेमिक SQL की कोई आवश्यकता नहीं है। तेज़, आसान।

  • RETURN NEW का उपयोग करें इसके बजाय RETURN NULL इन ट्रिगर फ़ंक्शंस में जब तक आप नहीं जानते कि आप क्या कर रहे हैं। (NULL INSERTको रद्द कर देगा वर्तमान पंक्ति के लिए।)

  • यह सरल संस्करण मानता है कि प्रत्येक तालिका (और दृश्य) में id . नामक एक अद्वितीय कॉलम होता है . एक अधिक परिष्कृत संस्करण प्राथमिक कुंजी का गतिशील रूप से उपयोग कर सकता है।

  • UPDATE के लिए कार्य दृश्य और तालिका के स्तंभों को किसी भी क्रम में होने देता है , जब तक सेट समान है। INSERT . के लिए फ़ंक्शन दृश्य और तालिका के कॉलम समान क्रम में होने की अपेक्षा करता है . यदि आप मनमानी क्रम की अनुमति देना चाहते हैं, तो INSERT . में एक कॉलम परिभाषा सूची जोड़ें कमांड, ठीक उसी तरह जैसे UPDATE . के साथ ।

  • अपडेट किए गए संस्करण में id . में परिवर्तन भी शामिल हैं OLD . का उपयोग करके कॉलम इसके अतिरिक्त।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL के लिए कस्टम ट्रिगर आधारित उन्नयन

  2. PostgreSQL सरणी को PHP सरणी में बदलें

  3. PostgreSQL के EXPLAIN ANALYZE का MySQL समतुल्य क्या है?

  4. PostgreSQL DATEADD () समतुल्य

  5. समूहन/एकत्रीकरण के दौरान सरणी मानों को संयोजित/मर्ज करें