2009-11-25 9 views
20

(नोट:। नीचे अपनाया जवाब के साथ अद्यतन)PostgreSQL: अद्यतन विभाजन भर में इस कदम का तात्पर्य

एक PostgreSQL 8.1 (या बाद में) विभाजित तालिका के लिए, कैसे एक एक UPDATE ट्रिगर और प्रक्रिया के लिए "चाल" को परिभाषित करता है एक विभाजन से दूसरी तरफ एक रिकॉर्ड, यदि UPDATE विभाजन खंड में परिवर्तन को परिभाषित करता है जो विभाजन पृथक्करण को परिभाषित करता है?

create table RECORDS (RECORD varchar(64) not null, ACTIVE boolean default true); 
create table ACTIVE_RECORDS (check (ACTIVE)) inherits RECORDS; 
create table INACTIVE_RECORDS (check (not ACTIVE)) inherits RECORDS; 

INSERT ट्रिगर और समारोह काम अच्छी तरह से: नई सक्रिय रिकॉर्ड एक तालिका में डाल दिया हो, और नए निष्क्रिय रिकॉर्ड

उदाहरण के लिए, मैं एक मेज रिकॉर्ड तो जैसे सक्रिय और निष्क्रिय रिकॉर्ड में विभाजित है दूसरे में। मैं UPDATE एस को सक्रिय क्षेत्र में एक एक वंशज से दूसरे में एक रिकॉर्ड को "स्थानांतरित" करने के लिए चाहता हूं, लेकिन मुझे एक त्रुटि आ रही है जो बताती है कि यह संभव नहीं हो सकता है।

उत्प्रेरक विनिर्देश और त्रुटि संदेश:

pg=> CREATE OR REPLACE FUNCTION record_update() 
    RETURNS TRIGGER AS $$ 
    BEGIN 
     IF (NEW.active = OLD.active) THEN 
     RETURN NEW; 
     ELSIF (NEW.active) THEN 
     INSERT INTO active_records VALUES (NEW.*); 
     DELETE FROM inactive_records WHERE record = NEW.record; 
     ELSE 
     INSERT INTO inactive_records VALUES (NEW.*); 
     DELETE FROM active_records WHERE record = NEW.record; 
     END IF; 
     RETURN NULL; 
    END; 
    $$ 
    LANGUAGE plpgsql; 

pg=> CREATE TRIGGER record_update_trigger 
     BEFORE UPDATE ON records 
     FOR EACH ROW EXECUTE PROCEDURE record_update(); 

pg=> select * from RECORDS; 
record | active 
--------+-------- 
foo | t   -- 'foo' record actually in table ACTIVE_RECORDS 
bar | f   -- 'bar' record actually in table INACTIVE_RECORDS 
(2 rows) 

pg=> update RECORDS set ACTIVE = false where RECORD = 'foo'; 
ERROR: new row for relation "active_records" violates check constraint "active_records_active_check" 

ट्रिगर प्रक्रिया के साथ बजाना (लौटने शून्य और आगे) मेरे लिए पता चलता है कि बाधा चेक किया गया है, और त्रुटि, उठाया से पहले अपने ट्रिगर शुरू हो जाती है, जिसका अर्थ है कि मेरा वर्तमान दृष्टिकोण काम नहीं करेगा। क्या यह काम करने के लिए मिल सकता है?

अद्यतन/उत्तर

नीचे UPDATE ट्रिगर प्रक्रिया मैं का उपयोग कर, विभाजन को दिए गये उसी प्रक्रिया समाप्त हो गया है। क्रेडिट Bell को पूरी तरह से है, जिसका जवाब मुझे कुंजी जानकारी दी विभाजन पर ट्रिगर:

CREATE OR REPLACE FUNCTION record_update() 
RETURNS TRIGGER AS $$ 
BEGIN 
    IF ((TG_TABLE_NAME = 'active_records' AND NOT NEW.active) 
     OR 
     (TG_TABLE_NAME = 'inactive_records' AND NEW.active)) THEN 
    DELETE FROM records WHERE record = NEW.record; 
    INSERT INTO records VALUES (NEW.*); 
    RETURN NULL; 
    END IF; 

    RETURN NEW; 
END; 
$$ 
LANGUAGE plpgsql; 
+0

आपका "उदाहरण" अधूरा है: "partitioned_records" के लिए परिभाषा लापता; आप "partitioned_records" के लिए एक ट्रिगर परिभाषित करते हैं लेकिन "रिकॉर्ड्स" से चुनें और अपडेट करें। –

+0

@ मिलन, धन्यवाद - कट'नपेस्ट त्रुटियां। उपाय करेंगे – pilcrow

+0

जब आप आंशिक अनुक्रमणिका का उपयोग कर सकते हैं तो इस संदर्भ में विभाजन का उपयोग करने का क्या मतलब है? – kalu

उत्तर

17

यह काम करने के लिए बनाया जा सकता है, ट्रिगर कि इस कदम से करता है बस जरूरत है, प्रत्येक विभाजन के लिए परिभाषित किया जा करने के लिए नहीं पूरी मेज तो शुरू के रूप में आप तालिका परिभाषा के लिए किया था और सम्मिलित करें ट्रिगर

CREATE TABLE records (
record varchar(64) NOT NULL, 
active boolean default TRUE 
); 

CREATE TABLE active_records (CHECK (active)) INHERITS (records); 
CREATE TABLE inactive_records (CHECK (NOT active)) INHERITS (records); 

CREATE OR REPLACE FUNCTION record_insert() 
RETURNS TRIGGER AS $$ 
BEGIN 
    IF (TRUE = NEW.active) THEN 
    INSERT INTO active_records VALUES (NEW.*); 
    ELSE 
    INSERT INTO inactive_records VALUES (NEW.*); 
    END IF; 
    RETURN NULL; 
END; 
$$ 
LANGUAGE plpgsql; 

CREATE TRIGGER record_insert_trigger 
BEFORE INSERT ON records 
FOR EACH ROW EXECUTE PROCEDURE record_insert(); 

... चलो कुछ परीक्षण डेटा है ...

INSERT INTO records VALUES ('FirstLittlePiggy', TRUE); 
INSERT INTO records VALUES ('SecondLittlePiggy', FALSE); 
INSERT INTO records VALUES ('ThirdLittlePiggy', TRUE); 
INSERT INTO records VALUES ('FourthLittlePiggy', FALSE); 
INSERT INTO records VALUES ('FifthLittlePiggy', TRUE); 

अब विभाजन पर चलाता। यदि NEW.active = OLD.active चेक सक्रिय के मूल्य की जांच करने में निहित है क्योंकि हम जानते हैं कि तालिका में पहले स्थान पर क्या होने की अनुमति है।

CREATE OR REPLACE FUNCTION active_partition_constraint() 
    RETURNS TRIGGER AS $$ 
    BEGIN 
     IF NOT (NEW.active) THEN 
     INSERT INTO inactive_records VALUES (NEW.*); 
     DELETE FROM active_records WHERE record = NEW.record; 
     RETURN NULL; 
     ELSE 
     RETURN NEW; 
     END IF; 
    END; 
    $$ 
    LANGUAGE plpgsql; 

CREATE TRIGGER active_constraint_trigger 
    BEFORE UPDATE ON active_records 
    FOR EACH ROW EXECUTE PROCEDURE active_partition_constraint(); 

CREATE OR REPLACE FUNCTION inactive_partition_constraint() 
    RETURNS TRIGGER AS $$ 
    BEGIN 
     IF (NEW.active) THEN 
     INSERT INTO active_records VALUES (NEW.*); 
     DELETE FROM inactive_records WHERE record = NEW.record; 
     RETURN NULL; 
     ELSE 
     RETURN NEW; 
     END IF; 
    END; 
    $$ 
    LANGUAGE plpgsql; 

CREATE TRIGGER inactive_constraint_trigger 
    BEFORE UPDATE ON inactive_records 
    FOR EACH ROW EXECUTE PROCEDURE inactive_partition_constraint(); 

... और परीक्षण परिणाम ...

scratch=> SELECT * FROM active_records; 
     record  | active 
------------------+-------- 
FirstLittlePiggy | t 
ThirdLittlePiggy | t 
FifthLittlePiggy | t 
(3 rows) 

scratch=> UPDATE records SET active = FALSE WHERE record = 'ThirdLittlePiggy'; 
UPDATE 0 
scratch=> SELECT * FROM active_records; 
     record  | active 
------------------+-------- 
FirstLittlePiggy | t 
FifthLittlePiggy | t 
(2 rows) 

scratch=> SELECT * FROM inactive_records; 
     record  | active 
-------------------+-------- 
SecondLittlePiggy | f 
FourthLittlePiggy | f 
ThirdLittlePiggy | f 
(3 rows) 
+0

@ बेल, अच्छा जवाब (और अच्छी टोपी)। मुझे लगता है कि आपको यह मिल गया है, और, यदि हां, तो मुझे सत्यापित होने के बाद आपको हरे रंग की चेकमार्क मिल जाएगी! – pilcrow

+0

तो संक्षेप में, मुझे प्रत्येक विभाजन पर प्रत्येक सम्मिलन के लिए एक ट्रिगर में विभाजन तर्क को फिर से लागू करने की आवश्यकता है? –

+0

@ डेविड नाथन - नहीं। पोस्टर्स द्वारा INSERT (या COPY) संचालन के लिए तर्क प्रदान किया जाता है।प्रश्न और समाधान UPDATE को संभालने के बारे में हैं जब अद्यतन रिकॉर्ड मूल से अलग विभाजन में होगा। – Bell

संबंधित मुद्दे