2010-02-13 11 views
5

Tablodaki kayıtların revizyonlarını takip etmeliyim. Yaptığım şey, ilkinden devralınan ve bir revizyon sayacı ekleyen ikinci bir tablo oluşturmak.postgresql'deki revizyonları izleme

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

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

Ardından, A her eklendiğinde/güncellendiğinde, B tablosunu güncelleyen bir tetikleyici oluşturdum. Anlayamadığım şey, B.revision'un her bir kimlik için bir "sıra" tutmasını nasıl sağlamanız gerektiğidir.

Örnek: A tablosunun 2 satırı vardır, i & j.
i 3 kez güncellendi ve 3 düzeltmesi olmalı: (1, 2, 3).
j 2 defa güncellendi ve iki kez düzeltme yapılıyor: (1, 2).

Şimdiye kadar sahip olduğum şey, belki yanlış yoldan aşağı iniyorum ve birisi bana yardım edebilir!

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; 

Değiştim bir COALESCE içine "bulunamadı eğer" hayır mevcut revizyon varsa o "0" bulacaktır:

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(); 

cevap

7

sürüm numaralarını sadece için gerekirse Sipariş vermek ve özel olarak her bir tanımlayıcı için bir tane artıran bir tamsayıya gerek duymayın, bunu yapmanın en kolay yolu, düzeltme için bir sıra kullanmak ve sizin için izlemeyi izin vermek:

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(); 

Ardından ekleri her zamanki gibi yapın:

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) 
Yani şöyle belirli bir satıra tüm revizyonları alabilirsiniz: Audit Trigger:

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

Bu çok anlam ifade ediyor. En iyisi OP'nin gerekliliklerini değiştirmek için gerekliliklerini değiştirmesidir, çünkü başka şeylerin bahsettiğiniz gibi kilitlenmesi gerekir. –

+1

Hrm. Ve sadece gerçek revizyon bilgilerini göstermediğini fark ettim. R1'deki rekoru "bar" olarak ekledim ve r3'te "siz" olarak güncelledim, ancak bu son sorgudaki sonuçlar her iki revizyon için "siz" i gösteriyor. Bunu düzeltmek için B, B'den miras almamalı ve “DAHA FAZLA” yerine “LASE” yi kullanmalıdır: “CREABLE TABLE B (LIKE A, revizyon seri NOT NULL); – theory

+0

Veya "yalnızca" anahtar sözcüğünü kullanın. Ama evet, ayrı tabloları kullanmak daha az kafa karıştırıcı olabilir. –

0

İşte benim öneri. Ardından, ardıl revizyonu ile sıraya B'yi ekliyorum.

senin miras konusunda dikkatli olun, aşağıdaki gibi, seçme ve güncelleme sırasında bir tabloya kendinizi sınırlamak için "sadece" anahtar kelime kullanmak gerekir:

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

Bu çözüm bir yarış koşuluna sahiptir. Yarış koşullarından kaçınmak için, eki yapmadan önce B'deki tüm kayıtları "id = NEW.id" ile kilitlemeniz gerekir. Bir dizinin kullanılması, yarış koşulunu önler ve bunun için kilit gerektirmez. – theory

+0

Bu nedenle, SELECT FOR UPDATE * FROM B WHERE id = NEW.id eklemeniz gerekir, aynı zamanda yerine yeni bir revizyon kimliği almak için COALESCE (MAX (revizyon) +1,0) olmalıdır. –

+0

Anlaşılan bu kod eşzamanlı erişim ile çalışmaz. Yarış koşullarıyla uğraşmak istiyorsak, id başına tek bir ardışık sıraya sahip olma yeteneğini kaybederiz. –

-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

Lütfen http://stackoverflow.com/editing-help#code adresinden bir göz atın ve cevabınızı "düzenlemeye" çalışın, böylece kod yapışır. Cevabınızı nasıl düzenleyeceğimi bilmiyordum, çünkü ne yaptığınızı takip edemedim ... – kratenko

0

ben geçmişte kullandığınız postgres'in bir özellik zengin Aduit paketidir. Güncelleme türünü (ekleme, güncelleme, silme) ve güncellemenin önceki ve sonraki değerlerini izler.