是否可以防止删除 PostgreSQL 端表中的第一行?
我有一个类别表,我想防止删除默认类别,因为它可能会破坏应用程序。当然,我可以在应用程序代码中轻松地做到这一点,但在数据库中做到这一点会好得多。
我认为这与删除语句的规则有关,但我在文档中找不到任何与我的问题很接近的东西。
是否可以防止删除 PostgreSQL 端表中的第一行?
我有一个类别表,我想防止删除默认类别,因为它可能会破坏应用程序。当然,我可以在应用程序代码中轻松地做到这一点,但在数据库中做到这一点会好得多。
我认为这与删除语句的规则有关,但我在文档中找不到任何与我的问题很接近的东西。
你对规则系统的思考是对的。这是与您的问题匹配的示例的链接。它甚至比触发器更简单:
create rule protect_first_entry_update as
on update to your_table
where old.id = your_id
do instead nothing;
create rule protect_first_entry_delete as
on delete to your_table
where old.id = your_id
do instead nothing;
有些答案漏掉了一点:受保护行的更新也必须受到限制。否则,可以首先更新受保护的行,使其不再满足禁止删除标准,然后可以删除更新的行,因为它不再受保护。
您想在表上定义一个 BEFORE DELETE触发器。当您尝试删除该行(通过 PK 匹配或具有单独的“保护”布尔列)时,引发异常。
我不熟悉 PostgreSQL 语法,但看起来你会这样做:
CREATE FUNCTION check_del_cat() RETURNS trigger AS $check_del_cat$
BEGIN
IF OLD.ID = 1 /*substitute primary key value for your row*/ THEN
RAISE EXCEPTION 'cannot delete default category';
END IF;
END;
$check_del_cat$ LANGUAGE plpgsql;
CREATE TRIGGER check_del_cat BEFORE DELETE ON categories /*table name*/
FOR EACH ROW EXECUTE PROCEDURE check_del_cat();
我认为实现此目的的最佳方法是在此表上创建删除触发器。基本上,您必须编写一个存储过程以确保此“默认”类别将始终存在,然后使用此表上的触发器 ON DELETE 事件强制执行它。做到这一点的一个好方法是创建一个每行触发器,以保证在 DELETE 事件上永远不会删除“默认”类别行。
请查看 PostgreSQL 关于触发器和存储过程的文档:
http://www.postgresql.org/docs/8.3/interactive/trigger-definition.html
http://www.postgresql.org/docs/8.3/interactive/plpgsql.html
这个 wiki 中也有一些有价值的例子:
http://wiki.postgresql.org/wiki/A_Brief_Real-world_Trigger_Example
您可以在另一个表(称为默认值)中有一行引用默认类别。FK 约束不允许删除默认类别。
请记住触发器的工作原理。他们将为您的删除语句将删除的每一行触发。这并不意味着您不应该使用触发器,只需牢记这一点,最重要的是测试您的使用场景并确保性能满足要求。
我应该使用规则还是触发器?
来自官方文档:“对于两者都可以实现的东西,最好取决于数据库的使用情况。触发器会为任何受影响的行触发一次。规则操纵查询或生成附加查询。所以如果许多行在一条语句中受到影响,发出一个额外命令的规则可能比为每一行调用并且必须多次执行其操作的触发器更快。但是,触发器方法在概念上比规则方法简单得多,并且新手更容易做对。”
有关详细信息,请参阅文档。
http://www.postgresql.org/docs/8.3/interactive/rules-triggers.html