2010-02-13 25 views
5

Tengo que hacer un seguimiento de las revisiones de los registros en una tabla. Lo que hice fue crear una segunda tabla que hereda de la primera y agrega un contador de revisión.revisar las revisiones en postgresql

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

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

Luego creé un disparador que actualizaría la tabla B cada vez que se inserta o actualiza A. Lo que no puedo entender es cómo hacer que B.revision mantenga una "secuencia" individual para cada identificación.

Ejemplo: la tabla A tiene 2 filas, i & j.
i ha sido actualizado 3 veces y debe tener 3 revisiones: (1, 2, 3).
j se ha actualizado 2 veces y debe tener dos revisiones: (1, 2).

Esto es lo que tengo hasta ahora, ¡tal vez estoy tomando el camino equivocado y alguien puede ayudarme!

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

Respuesta

7

Si necesita los números de versión sólo para ordenando, y no necesita específicamente que sean un número entero que aumente en uno para cada identificador, la forma más fácil de hacerlo es usar una secuencia para la revisión y dejar que haga el seguimiento por usted:

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

Luego haga las inserciones como de costumbre:

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) 

para que pueda obtener todas las revisiones para una fila determinada de esta manera:

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

Esto tiene mucho sentido. Sería mejor que el OP cambie sus requisitos para hacer espacio para esto, porque de otra manera las cosas requerirían bloqueo como usted menciona. –

+1

Hrm. Y acabo de notar que no muestra la información de revisión real. Inserté el registro en r1 como "barra" y lo actualicé en r3 como "usted", pero los resultados en esa última consulta muestran "usted" para ambas revisiones. Para solucionar eso, B no debe heredar de A. use 'LIKE' en lugar de' INHERITS' para desacoplarlos: 'CREATE TABLE B (LIKE A, revisión serial NOT NULL);'. – theory

+0

O use la palabra clave "only". Pero sí, podría ser menos confuso usar tablas separadas. –

0

aquí está mi sugerencia:

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; 

he cambiado el "si no se encuentra" en una coalescencia, que escogerá el "0" si no hay una revisión existente. Luego, inserto en B la fila, con la revisión incrementada.

tener cuidado con su herencia: necesitará utilizar la palabra clave "sólo" por qué limitarse a la Una tabla en la selección y actualización, como por ejemplo:

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

Esta solución tiene una condición de carrera. Para evitar la condición de carrera, debe bloquear todos los registros en B con 'id = NEW.id' antes de poder hacer la inserción. El uso de una secuencia evita la condición de carrera y, por lo tanto, no requiere bloqueo. – theory

+0

Por lo tanto, debe agregar un SELECCIONAR PARA ACTUALIZAR * DESDE B DONDE id = NEW.id, también debe ser COALESCE (MAX (revisión) +1,0) para obtener una nueva Id. De revisión en lugar de la misma. –

+0

De acuerdo, este código no funcionaría con el acceso concurrente. Si queremos lidiar con las condiciones de carrera, perderíamos la capacidad de tener una única secuencia consecutiva por identificación. –

-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

eche un vistazo a http://stackoverflow.com/editing-help#code e intente 'editar' su respuesta, para que el código sobresalga. No sabía cómo editar tu respuesta, porque no podía seguir lo que estás haciendo ... – kratenko

0

Aquí es un rico conjunto Aduit función de postgres que he utilizado en el pasado: Audit Trigger. Realiza un seguimiento del tipo de actualización (insertar, actualizar, eliminar), así como los valores anteriores y posteriores de la actualización.

Cuestiones relacionadas