How to make PostgreSQL insert a row into a table when deleted from another table?

前端 未结 2 1384
星月不相逢
星月不相逢 2021-01-02 04:10

We have an application, which will delete a row from a table based on user requests. I cannot change the application code. However, I want to insert a row into another table

2条回答
  •  情话喂你
    2021-01-02 04:26

    Write a trigger function. Something like this:

    CREATE OR REPLACE FUNCTION trg_backup_row()
      RETURNS trigger AS
    $BODY$
    BEGIN
    
    INSERT INTO other_tbl
    SELECT (OLD).*, t.other_col                -- all columns of from old table
    -- SELECT OLD.col1, OLD.col2, t.other_col  -- alternative: some cols from old tbl
    FROM   third_tbl t
    WHERE  t.col = OLD.col  -- link to third table with info from deleted row
    AND    ;
    
    RETURN NULL;
    
    END;
    $BODY$
      LANGUAGE plpgsql VOLATILE;
    

    And a trigger ON DELETE. Like this:

    CREATE TRIGGER delaft
      AFTER DELETE
      ON tbl
      FOR EACH ROW
      EXECUTE PROCEDURE trg_backup_row();
    

    Key elements

    • Best make it a trigger AFTER DELETE and FOR EACH ROW.

    • To return all columns from the old table use the syntax (OLD).*. See the manual about accessing composite types. Alternatively OLD.* is valid syntax, too, because OLD is added to the FROM clause implicitly. For a VALUES expression it would have to be (OLD).*, though. Like:

      INSERT INTO other_tbl
      VALUES((OLD).*, some_variable)
      
    • You can include values from any other table like I demonstrate. Just make sure to get a single row, or you create multiple entries.

    • As the trigger fires AFTER the event, the function can RETURN NULL.


    About visibility

    In response to @couling's watchful comment.

    While foreign keys can be declared as DEFERRED, this will only defer the integrity check, not the deletion itself. Rows that are deleted in triggers executed before the one at hand or by ON DELETE CASCADE foreign keys will not be visible any more at the time this AFTER DELETE trigger is called. (It all happens in one transaction obviously. None of these details matter for other transactions, which will see all or none of the effects. Refer to the manual for more about the MVCC model and transaction isolation.)

    Therefore, if you want to include values from rows depending in such a way in your INSERT, be sure to call this trigger before those rows get deleted.

    You may have to you make this trigger BEFORE DELETE.

    Or it can mean that you have to order your triggers accordingly, BEFORE triggers come before AFTER triggers, obviously. And triggers at the same level are executed in alphabetical order.

    However, as long as I am super precise here, I might also add that changes made to the row (or depending rows) in other BEFORE triggers are also only visible if those are called before this one.

    My advice to make it an AFTER trigger was because it is less prone to complications and cheaper if other trigger might cancel (roll back) the DELETE half way through the operation - as long as none of the above applies.

提交回复
热议问题