2010-02-13 18 views
5

में ट्रैक संशोधन में मुझे एक तालिका में रिकॉर्ड्स के संशोधन का ट्रैक रखना होगा। मैंने जो किया है वह दूसरी तालिका बनाता है जो पहले से विरासत में आता है और एक संशोधन काउंटर जोड़ता है।पोस्टग्रेस्क्ल

CREATE TABLE A (
id SERIAL, 
foo TEXT, 
PRIMARY KEY (id)); 

CREATE TABLE B (
revision INTEGER NOT NULL) INHERITS (A); 

फिर मैंने एक ट्रिगर बनाया जो प्रत्येक बार ए को डाला/अपडेट किया गया है। मैं यह नहीं समझ सकता कि बीआरविजन को प्रत्येक आईडी के लिए एक व्यक्तिगत "अनुक्रम" कैसे बनाए रखना है।

उदाहरण: तालिका ए में 2 पंक्तियां हैं, i & जे।
मुझे 3 बार अपडेट किया गया है और इसमें 3 संशोधन होना चाहिए: (1, 2, 3)।
जे 2 बार अपडेट किया गया है और इसमें दो संशोधन होना चाहिए: (1, 2)।

यहां तक ​​कि मेरे पास अभी तक क्या है, शायद मैं गलत पथ पर जा रहा हूं और कोई मेरी मदद कर सकता है!

CREATE OR REPLACE FUNCTION table_update() RETURNS TRIGGER AS $table_update$ 
DECLARE 
    last_revision INTEGER; 
BEGIN 
    SELECT INTO last_revision coalesce(MAX(revision), 0) FROM B WHERE id = NEW.id; 

    INSERT INTO B SELECT NEW.*, last_revision + 1; 

    RETURN NEW; 
END; 
$table_update$ LANGUAGE plpgsql; 

मैं बदल एक सम्मिलित में "अगर नहीं मिला", कि "0" ले जाएगा अगर कोई मौजूदा संशोधन है:

CREATE OR REPLACE FUNCTION table_update() RETURNS TRIGGER AS $table_update$ 
    DECLARE 
     last_revision INTEGER; 
    BEGIN 
     SELECT INTO last_revision MAX(revision) FROM B WHERE id = NEW.id; 

     IF NOT FOUND THEN 
      last_revision := 0; 
     END IF; 

     INSERT INTO B SELECT NEW.*; 

     RETURN NEW; 
    END; 
$table_update$ LANGUAGE plpgsql; 

CREATE TRIGGER table_update 
AFTER INSERT OR UPDATE ON A 
    FOR EACH ROW EXECUTE PROCEDURE table_update(); 

उत्तर

7

तुम सिर्फ के लिए संस्करण संख्या की जरूरत है आदेश देना, और विशेष रूप से उन्हें एक पूर्णांक होने की आवश्यकता नहीं है जो प्रत्येक पहचानकर्ता के लिए एक द्वारा बढ़ाया जाए, इसे करने का सबसे आसान तरीका संशोधन के लिए अनुक्रम का उपयोग करना है और बस इसे आपके लिए ट्रैकिंग करने दें:

CREATE TABLE A (
    id SERIAL, 
    foo TEXT, 
    PRIMARY KEY (id) 
); 

CREATE TABLE B (revision SERIAL NOT NULL) INHERITS (A); 

CREATE OR REPLACE FUNCTION table_update() RETURNS TRIGGER AS $table_update$ 
    BEGIN 
     INSERT INTO B SELECT NEW.*; 
     RETURN NEW; 
    END; 
$table_update$ LANGUAGE plpgsql; 

CREATE TRIGGER table_update 
AFTER INSERT OR UPDATE ON A 
    FOR EACH ROW EXECUTE PROCEDURE table_update(); 

फिर सामान्य रूप से आवेषण करें:

try=# insert into a (foo) values ('bar'); 
    INSERT 0 1 
    try=# insert into a (foo) values ('bar'); 
    INSERT 0 1 
    try=# update a set foo = 'you' where id = 1; 
    UPDATE 2 
    try=# select * from b; 
    id | foo | revision 
    ----+-----+---------- 
     2 | bar |  2 
     1 | you |  1 
     1 | you |  3 
    (3 rows) 

तो तुम तो जैसे किसी पंक्ति के लिए सभी संशोधन प्राप्त कर सकते हैं: Audit Trigger:

try=# select * from b where id = 1 order by revision; 
    id | foo | revision 
    ----+-----+---------- 
     1 | you |  1 
     1 | you |  3 
    (2 rows) 
+0

यह बहुत समझ में आता है। यह सबसे अच्छा होगा कि ओपी इसके लिए जगह बनाने के लिए अपनी आवश्यकताओं को बदलता है, क्योंकि अन्य बातों के अनुसार आपको लॉकिंग की आवश्यकता होगी। –

+1

एचआरएम। और मैंने अभी देखा है कि यह वास्तविक संशोधन जानकारी नहीं दिखाता है। मैंने आर 1 पर "बार" के रूप में रिकॉर्ड डाला और इसे "आप" के रूप में आर 3 में अपडेट किया, लेकिन उस अंतिम क्वेरी के परिणाम दोनों संशोधनों के लिए "आप" दिखाते हैं। इसे ठीक करने के लिए, बी को ए से प्राप्त नहीं होना चाहिए। उन्हें 'इनहेरिट्स' के बजाय 'LIKE' का उपयोग करने के लिए उन्हें उपयोग करना चाहिए: 'तालिका बी बनाएं (जैसे ए, पुनरीक्षण धारावाहिक न्यूल);'। – theory

+0

या "केवल" कीवर्ड का उपयोग करें। लेकिन हाँ, अलग टेबल का उपयोग करने के लिए यह कम भ्रमित हो सकता है। –

0

यहाँ मेरी सुझाव है। फिर, मैं बढ़ी हुई संशोधन के साथ पंक्ति में बी डालता हूं।

अपने विरासत के साथ सावधान रहें: आप, जब चयन करने और अद्यतन करने के अपने आप को एक मेज पर सीमित करने के लिए "केवल" कीवर्ड का उपयोग करने जैसे की आवश्यकता होगी:

select * from only A 
update only A set foo = ... where id = ... 
+0

इस समाधान में रेस की स्थिति है। दौड़ की स्थिति से बचने के लिए, आपको सम्मिलित करने से पहले 'id = NEW.id' के साथ बी में सभी रिकॉर्ड्स को लॉक करना होगा। अनुक्रम का उपयोग दौड़ की स्थिति से बचाता है और इसके लिए कोई लॉक की आवश्यकता नहीं होती है। – theory

+0

तो आपको अद्यतन के लिए एक चयन जोड़ना चाहिए * बी से जहां id = NEW.id, इसके बजाय इसे एक नया संशोधन आईडी प्राप्त करने के लिए COALESCE (MAX (संशोधन) +1,0) होना चाहिए। –

+0

सहमत है, यह कोड समवर्ती पहुंच के साथ काम नहीं करेगा। यदि दौड़ की स्थिति से निपटना चाहते हैं, तो हम प्रति आईडी लगातार एक अनुक्रम प्राप्त करने की क्षमता खो देंगे। –

-1
--THIS TABLE AUTOMATICALLY INCREMENT THE COLUMN VALUES USING TRIGGER 
CREATE TABLE emp_table(
    emp_id int not null, 
    emp_name varchar not null, 
    emp_rollno int not null, 
    primary key(emp_id) 
); 

--Now create table with three column and emp_id is primary key 
--and emp_rollno both are automatically increment in trigger is fired 
CREATE or REPLACE FUNCTION emp_fun() RETURNS TRIGGER AS $BODY$ 
--creating function emp_fun() 
DECLARE 
BEGIN 
    IF(tg_op='INSERT') THEN 
    NEW.emp_id=COALESCE((SELECT MAX(emp_id)+1 FROM emp_table), 1); 
    NEW.emp_rollno=COALESCE((SELECT MAX(emp_rollno)+1 FROM emp_table), 1); 
    --trigger is fired values is automatically increment 
END IF; 

IF tg_op='DELETE' THEN RETURN OLD; ELSE RETURN NEW; END IF; 
END; $BODY$LANGUAGE PLPGSQL 

CREATE TRIGGER emp_fun BEFORE INSERT ON 
    emp_table FOR EACH ROW EXECUTE PROCEDURE emp_fun(); 

INSERT INTO emp_table(emp_name) VALUES('BBB'); 
--insert the value tanle emp_table 
SELECT * FROM emp_table 
-- Check the result 
+0

कृपया http://stackoverflow.com/editing-help#code पर एक नज़र डालें और अपना उत्तर 'संपादित करें' करने का प्रयास करें, ताकि कोड चिपक जाए। मुझे नहीं पता था कि आपका जवाब कैसे संपादित करें, क्योंकि मैं जो भी कर रहा हूं उसका पालन नहीं कर सका ... – kratenko

0

यहाँ postgres है कि मैं पहले उपयोग किए गए के लिए एक सुविधा अमीर Aduit पैकेज है। यह अद्यतन के प्रकार (सम्मिलित, अद्यतन, हटाएं) के साथ-साथ अद्यतन के लिए पहले और बाद के मानों को ट्रैक करता है।

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