Postgres 9.2 - 添加条件约束检查
Posted
技术标签:
【中文标题】Postgres 9.2 - 添加条件约束检查【英文标题】:Postgres 9.2 - add conditional constraint check 【发布时间】:2013-02-07 20:59:05 【问题描述】:我使用的是 PostgreSQL 9.2,需要在列上添加条件约束。本质上,我想确保当其他两列具有特定值时,一列为假。
gid | int_unsigned | not null default 0
realm | character varying(255) | not null default ''::character varying
grant_update | smallint_unsigned | not null default (0)::smallint
grant_delete | smallint_unsigned | not null default (0)::smallint
例子:
alter table node_access add constraint block_anonymous_page_edit
check (grant_update = 0 WHERE (gid = 1 AND realm = 'nodeaccess_rid'));
这应该做的是确保当 gid 为 1 且 realm = nodeaccess_rid 时 grant_update 等于 0。但是,我认为与其做我想做的事,不如说它实际上是在尝试让所有列都模仿这些值。本质上,它试图确保grant_update 始终为0,gid 始终为1,并且realm 始终为nodeaccess_rid。我得到的错误是:
ERROR: check constraint "block_anonymous_page_edit" is violated by some row
编辑
我认为这必须是一个在更新时触发的函数。
编辑
我在上面的问题中添加了一行,因此更新了已批准的解决方案,并在下面添加了评论。
【问题讨论】:
int_unsigned
和 smallint_unsigned
在 Postgres 中是不存在的类型。请清理您的问题。
不存在与否,这就是我们的数据库滚动的方式。就目前而言,这个问题是正确的。
【参考方案1】:
一旦你围绕逻辑思考,这很简单CHECK
constraint:
CREATE TABLE tbl (
gid int NOT NULL DEFAULT 0
, realm text NOT NULL DEFAULT ''
, grant_update smallint NOT NULL DEFAULT 0
, CONSTRAINT block_anonymous_page_edit
CHECK (gid <> 1 OR realm <> 'nodeaccess_rid' OR grant_update = 0)
);
测试:
-- these work:
INSERT INTO tbl(gid, realm, grant_update)
VALUES (1, 'nodeaccess_rid', 0);
INSERT INTO tbl(gid, realm, grant_update)
VALUES (1, 'some_string', 1);
INSERT INTO tbl(gid, realm, grant_update)
VALUES (2, 'nodeaccess_rid', 1);
-- check violation!
INSERT INTO tbl(gid, realm, grant_update)
VALUES (1, 'nodeaccess_rid', 1);
db小提琴here
【讨论】:
我稍微修改了您的解决方案,以纳入我的问题中未包含的方面。还有一个附加属性允许用户或匿名用户删除页面,而不仅仅是更新它们。所以现在看起来像这样,CHECK (gid <> 1 OR realm <> 'nodeaccess_rid' OR grant_update = 0 OR grant_delete = 0)
实际的解决方案是这样的,alter table if exists node_access add constraint chk_block_anonymous_page_edit check (gid <> 1 or realm <> 'nodeaccess_rid' or grant_update = 0 or grant_delete = 0);
我假设您知道此约束允许grant_update
或 grant_delete
在上述情况下为0
,但不一定两者兼而有之。
正确。根据需要工作。感谢您的意见。
顺便说一下,我建议使用替代语法 CONSTRAINT my_check CHECK (gid 1 OR realm 'nodeaccess_rid' OR grant_update = 0) 给 CHECK 约束一个 NAME ...当您出于任何原因需要禁用、删除或更改约束时非常有用。【参考方案2】:
我会把它写成触发器。这使您可以灵活地提出错误(可能使用最适合测试的自定义代码)或仅处理问题并在 gid=1 和 realm = 'nodeaccess_rid' 时设置 grant_update = 0
【讨论】:
【参考方案3】:我最终选择了触发功能。这将检查角色并使用布尔型字段 grant_update 和 grant_delete 将不需要的功能设置为关闭。下面的函数还保留了 grant_view 值而不是覆盖它。
CREATE OR REPLACE function block_anonymous_page_edit()
RETURNS trigger AS $function$
BEGIN
IF NEW.gid = 1 AND NEW.realm != 'nodeaccess_author' AND (NEW.grant_update = 1 OR NEW.grant_delete = 1) THEN
RAISE WARNING 'Anonymous users are not allowed to edit pages.';
NEW.grant_update := 0;
NEW.grant_delete := 0;
END IF;
RETURN NEW;
END;
$function$ LANGUAGE plpgsql;
CREATE TRIGGER tgr_block_anonymous_page_edit BEFORE INSERT OR UPDATE ON node_access FOR EACH ROW EXECUTE PROCEDURE block_anonymous_page_edit();
【讨论】:
以上是关于Postgres 9.2 - 添加条件约束检查的主要内容,如果未能解决你的问题,请参考以下文章