2013-02-07 76 views
10

我正在使用PostgreSQL 9.2並需要在列上添加條件約束。基本上,我想確保當其他兩列具有特定值時,列是錯誤的。Postgres 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')); 

什麼,這是應該做的是確保grant_update等於0時,GID是1和境界= nodeaccess_rid。但是,我認爲不是做我想做的事情,而是試圖讓所有專欄模仿這些價值觀。實質上,它試圖確保grant_update始終爲0,gid始終爲1,並且領域始終爲nodeaccess_rid。我得到的錯誤是:

ERROR: check constraint "block_anonymous_page_edit" is violated by some row 

編輯

我認爲這會被這種大幹快上的更新觸發的功能。

編輯

我添加了一行,到上面的問題,因此更新了以下注釋的認可的解決方案。

+0

'int_unsigned'和'smallint_unsigned'是Postgres的不存在類型。請清理你的問題。 –

+0

不存在或不存在,這就是我們的數據庫如何滾動。目前的問題是正確的。 – thepriebe

回答

15

一旦你換你的頭腦圍繞它是一​​個相當簡單的​​邏輯:

CREATE TABLE tbl (
    gid   int  NOT NULL DEFAULT 0 
    ,realm  text  NOT NULL DEFAULT '' 
    ,grant_update smallint NOT NULL DEFAULT 0 
    ,CHECK (gid <> 1 
      OR realm <> 'nodeaccess_rid' 
      OR grant_update = 0) 
); 

測試:

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (1, 'nodeaccess_rid', 0);   -- works 

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (1, 'nodeaccess_rid', 1);   -- check violation! 

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (1, 'some_string', 1);   -- works 

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (2, 'nodeaccess_rid', 1);   -- works 
+0

我稍微改變了您的解決方案,以納入我沒有包含在我的問題中的一個方面。還有一個額外的屬性,允許用戶或匿名刪除頁面,而不僅僅是更新它們。所以現在看起來像這樣,'CHECK(gid <> 1 OR realm <>'nodeaccess_rid'或grant_update = 0或grant_delete = 0)' – thepriebe

+0

實際的解決方案看起來像這樣:alter table if exists node_access add constraint chk_block_anonymous_page_edit check gid <> 1或realm <>'nodeaccess_rid'或grant_update = 0或grant_delete = 0);' – thepriebe

+0

我假設您知道此限制允許'grant_update' *或*'grant_delete'爲所述情況的'0'但不一定是兩者。 –

3

我會寫這個作爲觸發器。這給你提供一個錯誤的靈活性(可能使用最適合測試的自定義代碼),或者只是處理問題,並在gid = 1時設置grant_update = 0,realm ='nodeaccess_rid'

0

我結束了帶觸發功能。這將檢查角色並使用boolean-ish字段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();