【问题标题】:CONSTRAINT to check values from a remotely related table (via join etc.)约束检查远程相关表中的值(通过连接等)
【发布时间】:2021-11-20 21:04:08
【问题描述】:

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

我有 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 添加一个约束,以检查role 中的type(“两个表之外”),例如:

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

我尝试使用JOINs 执行此操作,但没有成功。知道如何实现吗?

【问题讨论】:

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


    【解决方案1】:

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

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

    一种方法是使用像demonstrated by @Wolph 这样的触发器。

    一个干净的没有触发器的解决方案:添加冗余列并将它们包含在FOREIGN KEY constraints 中,这是强制引用完整性的首选。 dba.SE 上的相关答案以及详细说明:

    另一种选择是“伪造”IMMUTABLE 函数 进行检查并在 CHECK 约束中使用它。 Postgres 将允许这样做,但请注意可能的警告。最好将其设为NOT VALID 约束。见:

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 一个有连接的例子更适合这个问题。
      • 我也是这么想的。 OP的问题是关于检查相关表
      • CONSTRAINT TRIGGER一样。
      【解决方案3】:

      ...我这样做了(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();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多