Conditional CASCADE operation for foreign key constraint?

好久不见. 提交于 2019-12-24 01:54:43

问题


I have parent and child table where child has a FK pointing to the PK of parent table. When I delete something in parent table I can have child records deleted as well by having ON DELETE CASCADE.

However, in my parent table I don't delete records at all. Instead I set the column state = "passive". I want to delete related entries in the child table.

Do we have something like a "conditional CASCADE" in Postgres? Or is the solution to manually delete entries in the child table?


回答1:


You would have to do this in a trigger that takes action ON UPDATE. Where the NEW.state = "passive", delete the child rows.




回答2:


There is nothing like "conditional CASCADE". The closest thing that comes to mind would be to disable triggers. But that's not helpful in your case.

Assumptions:
- state is defined NOT NULL.
- parent_id never changes. If it does you'll want to cascade that UPDATE as well.

The condition to fire the trigger ON UPDATE should be:

     NEW.state =  "passive"
AND  OLD.state <> "passive"

.. since you do not want to trigger it over and over again, only once when parent is set to "passive".

CREATE OR REPLACE FUNCTION trg_upbef()
  RETURNS TRIGGER AS
$func$
BEGIN

DELETE FROM child
WHERE  parent_id = OLD.parent_id;  -- OLD works for UPDATE & DELETE

RETURN NEW;
END
$func$ LANGUAGE plpgsql;

Instead of checking the condition in the trigger function, you can do that in the trigger directly since Postgres 9.0, thereby saving a bit of overhead:

CREATE TRIGGER upd_cascade_del
BEFORE UPDATE ON parent
FOR EACH ROW
WHEN (NEW.state =  "passive" AND
      OLD.state <> "passive")      -- parenthesis required
EXECUTE PROCEDURE trg_upbef();

Don't forget to add a trigger for ON DELETE as well. You don't normally DELETE, but if you do, you want to either raise an exception or cascade the operation.
Trigger function has to RETURN OLD, since NEW is not defined in this case. Otherwise the same:

CREATE OR REPLACE FUNCTION trg_delbef()
...    
RETURN OLD;
...
$func$ LANGUAGE plpgsql;


CREATE TRIGGER del_cascade_del
BEFORE DELETE ON parent
FOR EACH ROW
WHEN (OLD.state <> "passive")      -- only if not already passive
EXECUTE PROCEDURE trg_delbef();


来源:https://stackoverflow.com/questions/18336871/conditional-cascade-operation-for-foreign-key-constraint

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!