2017-01-23 5 views
3

私のテストアプリケーションでは、PostgreSQL9.6インスタンスに次の設定のデータベースがあります。null以外の制約を持つPostgresqlの更新可能なビュー

CREATE TABLE public.parties 
(
    id integer NOT NULL DEFAULT nextval('parties_id_seq'::regclass), 
    party_type_id text NOT NULL, 
    fullname text NOT NULL DEFAULT ''::text, 
    created_at timestamp without time zone NOT NULL DEFAULT now(), 
    CONSTRAINT parties_pkey PRIMARY KEY (id, party_type_id), 

    (... extra sql not relevant to the question ...) 
); 

CREATE TABLE public.party_people 
(
    id integer NOT NULL, 
    gender text NOT NULL DEFAULT ''::text, 
    CONSTRAINT party_people_pkey PRIMARY KEY (id), 

    (... extra sql not relevant to the question ...) 
); 


CREATE OR REPLACE VIEW public.people AS 
SELECT t1.id, 
    t1.party_type_id, 
    t1.fullname, 
    t2.gender, 
    t1.created_at 
    FROM parties t1 
    JOIN party_people t2 ON t1.id = t2.id; 


CREATE OR REPLACE FUNCTION public.people_vw_update_func() 
    RETURNS trigger AS 
    LANGUAGE plpgsql 
    $BODY$  
    BEGIN 
    IF TG_OP = 'INSERT' THEN 
     IF NEW.id IS NULL THEN 
     NEW.id = NEXTVAL('parties_id_seq'); 
     END IF; 

     INSERT INTO parties 
     VALUES (NEW.id, NEW.party_type_id, NEW.fullname, NEW.created_at); 

     INSERT INTO party_people 
     VALUES (NEW.id, NEW.party_type_id, NEW.gender); 
     RETURN NEW; 
    ELSIF 
     (... extra sql to deal with DELETE and UPDATE cases ...) 
    END IF; 
    RETURN NEW; 
    END; 
    $BODY$ 

CREATE TRIGGER people_vw_update_trig 
    INSTEAD OF INSERT OR UPDATE OR DELETE 
    ON people 
    FOR EACH ROW 
    EXECUTE PROCEDURE people_vw_update_func(); 

私は私が代わりに手動で両方のテーブル間でデータを分割するクエリを書くのpeopleビューを介して個人データを管理することができpostgresので更新可能なビューを作成しようとしています。

私はビューのバッキングテーブルのNON NULL制約を持つことができないでそれ以外のようなクエリに実行している問題:

INSERT INTO people (fullname, gender) 
VALUES ("James Jones", "male"); 

created_atであるため、制約の失敗とでNEW.create_atためだろうトリガ機能は明らかにNULL

だから、私の質問はされています 誰がRずに更新可能なビューの内部NON NULL制約を処理するための方法を知ってい以下のようなものにesorting:

IF NEW.created_at IS NULL THEN 
    INSERT INTO parties 
    VALUES (NEW.id, NEW.party_type_id, NEW.fullname); 
ELSE  
    INSERT INTO parties 
    VALUES (NEW.id, NEW.party_type_id, NEW.fullname, NEW.created_at); 
END IF; 

をソリューションは本当に速い本当に厄介になるだろう、その後、さらに多くがあった場合、そのソリューションは、単一の列のために働くだろうが。

EDIT

最後に私がマッドサイエンティストが推奨するソリューションを実装しました。将来的にこの質問つまずくことがあり、誰のために私の最終的な解決策は:私がしなければならなかったすべてはビューなどの適切な表の値を取ると設定されたビュー、トリガで

ALTER TABLE people 
    ALTER COLUMN created_at SET DEFAULT now() 

その方法変数NEWにデフォルト値(ここではNULL)を入力してください。

答えて

2

テーブルだけでなく、ビューにデフォルト値を作成することもできます。更新可能なビューを持っている場合は、基になるテーブルのデフォルト値を追加するだけです。 NOT NULL制約は基になるテーブルによって強制できますが、INSTEAD OFトリガーは問題のNULLの代わりに値が指定されていなければデフォルト値を表示します。

ビューのデフォルト値の構文は、テーブルのデフォルト値を変更する場合と同じです。

1

あなたはただ行うことができます。

IF NEW.created_at IS NULL THEN 
    NEW.created_at = now() ; 
END IF ; 
/* Do the same for all columns requiring default values */ 

INSERT INTO 
     parties 
     (id,  party_type_id,  fullname,  created_at) 
VALUES 
     (NEW.id, NEW.party_type_id, NEW.fullname, NEW.created_at); 

かも

INSERT INTO 
     parties 
     (id,  party_type_id,  fullname,  created_at) 
VALUES 
     (NEW.id, NEW.party_type_id, NEW.fullname, coalesce(NEW.created_at, now())); 

documentation on Coalesceを確認してください。

+1

+1は、合体機能を推奨します。それは私が探していた正確な解決策でしたが、最終的に私は狂った科学者たちの答えに行きました。 – Zerodestiny

関連する問題