CONSTRAINT检查远程相关表中的值(通过连接等)

时间:2014-11-24 14:24:31

标签: postgresql database-design foreign-keys constraints referential-integrity

我想添加一个约束来检查相关表中的值。

我有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中添加一个约束type来检查role中的ALTER TABLE somethink_usr_rel ADD CONSTRAINT CH_sm_usr_type_check CHECK (usr.role.type = 'SOME_ENUM'); ("两张桌子以及#34;),例如:

JOIN

我尝试用{{1}}来做这件事,但没有成功。知道如何实现吗?

3 个答案:

答案 0 :(得分:19)

CHECK约束目前无法引用其他表。 The manual:

  

目前,CHECK表达式不能包含子查询,也不能引用   除当前行的列之外的变量。

一种方法是使用demonstrated by @Wolph之类的触发器。

没有触发器的干净解决方案:添加冗余列并将其包含在FOREIGN KEY约束中,这是强制执行参照完整性的首选。关于dba.SE的相关答案及详细说明:

另一种选择是“伪造”IMMUTABLE函数进行检查并在CHECK约束中使用它。 Postgres将允许这一点,但要注意可能的后果。您最好使其成为NOT VALID约束。详细说明:

答案 1 :(得分:8)

如果需要连接,则不能选择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();

答案 2 :(得分:0)

...我这样做了(nazwa =用户名,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();