web-dev-qa-db-ja.com

リモートで関連するテーブルの値をチェックするCONSTRAINT(結合などを介して)

関連テーブルの値をチェックする制約を追加したいと思います。

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で制約を課したい場合はお知らせください。)

typeroleをチェックするsomethink_usr_relに制約を追加したい(「2つのテーブルから離れている」)。たとえば、

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

JOINsでこれを実行しようとしましたが、成功しませんでした。それを達成する方法はありますか?

21
lukaszrys

CHECK制約は現在、他のテーブルを参照できません。 マニュアル:

現在、CHECK式にはサブクエリを含めることも、現在の行の列以外の変数を参照することもできません。

1つの方法は @ Wolphによって示される のようなトリガーを使用することです。

トリガーなしのクリーンソリューション:冗長な列を追加し、それらをFOREIGN KEY制約に含めます。これは、参照整合性を強制するための最初の選択肢です。詳細な手順を含むdba.SEに関する関連回答:

別のオプションは、チェックを実行して「偽」のIMMUTABLE関数を使用し、CHECK制約でそれを使用することです。 Postgresはこれを許可しますが、起こり得る結果に注意してください。あなたはそれをNOT VALID制約。詳細:

23

結合が必要な場合、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();
10
Wolph

...私はそうしました(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();
0
blackmoon