14

我想添加一個約束,將檢查相關表中的值。約束來檢查從遠程相關表(通過連接等)的值

我有3個表:

CREATE TABLE somethink_usr_rel (
    user_id BIGINT NOT NULL, 
    stomethink_id BIGINT NOT NULL 
); 

CREATE TABLE usr (
    id BIGINT NOT NULL, 
    role_id BIGINT NOT NULL 
); 

CREATE TABLE role (
    id BIGINT NOT NULL, 
    type BIGINT NOT NULL 
); 

(如果你要我把約束與FK讓我知道。)

我想一個約束添加到somethink_usr_rel,檢查在roletype(」兩張桌子遠「),例如:

ALTER TABLE somethink_usr_rel 
    ADD CONSTRAINT CH_sm_usr_type_check 
    CHECK (usr.role.type = 'SOME_ENUM'); 

我試着用JOIN s到這樣做,但沒有成功。任何想法如何實現它?

回答

16

CHECK限制目前還不能引用其他表。 Per documentation:

目前,CHECK表達式不能包含子查詢也不能引用除當前行字段之外 變量。

一種方法是使用像demonstrated by @Wolph這樣的觸發器。

乾淨的解決方案沒有觸發器(這是更強大的執行參照完整性)將添加冗餘列並將它們包含在FK約束。考慮dba.SE此密切相關的答案有詳細說明:

另一種選擇是「假」不可變的功能做檢查,並使用在CHECK約束。 Postgres會允許這樣做,但要注意可能的後果。你最好做一個約束。詳細信息:

7

A CHECK如果您需要連接,約束不是一個選項。您可以創建一個觸發器來引發錯誤。

有一個看看這個例子:http://www.postgresql.org/docs/9.1/static/plpgsql-trigger.html#PLPGSQL-TRIGGER-EXAMPLE

CREATE TABLE emp (
    empname text, 
    salary integer, 
    last_date timestamp, 
    last_user text 
); 

CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$ 
    BEGIN 
     -- Check that empname and salary are given 
     IF NEW.empname IS NULL THEN 
      RAISE EXCEPTION 'empname cannot be null'; 
     END IF; 
     IF NEW.salary IS NULL THEN 
      RAISE EXCEPTION '% cannot have null salary', NEW.empname; 
     END IF; 

     -- Who works for us when she must pay for it? 
     IF NEW.salary < 0 THEN 
      RAISE EXCEPTION '% cannot have a negative salary', NEW.empname; 
     END IF; 

     -- Remember who changed the payroll when 
     NEW.last_date := current_timestamp; 
     NEW.last_user := current_user; 
     RETURN NEW; 
    END; 
$emp_stamp$ LANGUAGE plpgsql; 

CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp 
    FOR EACH ROW EXECUTE PROCEDURE emp_stamp(); 
0

......我不是這樣(=由...用戶名,Firma跟=公司名稱):

CREATE TABLE users 
(
    id bigserial CONSTRAINT firstkey PRIMARY KEY, 
    nazwa character varying(20), 
    firma character varying(50) 
); 


CREATE TABLE test 
(
    id bigserial CONSTRAINT firstkey PRIMARY KEY, 
    firma character varying(50), 
    towar character varying(20), 
    nazwisko character varying(20) 
); 

ALTER TABLE public.test ENABLE ROW LEVEL SECURITY; 

CREATE OR REPLACE FUNCTION whoIAM3() RETURNS varchar(50) as $$ 
declare 
    result varchar(50); 
    BEGIN 
select into result users.firma from users where users.nazwa = current_user; 
    return result; 
    END; 

    $$ LANGUAGE plpgsql; 


CREATE POLICY user_policy ON public.test 
    USING (firma = whoIAM3()); 

CREATE FUNCTION test_trigger_function() 
RETURNS trigger AS $$ 
BEGIN 
    NEW.firma:=whoIam3(); 
return NEW; 
END 
$$ LANGUAGE 'plpgsql' 
CREATE TRIGGER test_trigger_insert BEFORE INSERT ON test FOR EACH ROW EXECUTE PROCEDURE test_trigger_function();