2017-01-23 3 views
3

В моем тестовом приложении у меня есть база данных со следующей настройкой на примере PostgreSQL9.6.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(); 

Я пытаюсь создать обновляемый вид в Postgres, где я могу, я могу управлять данными лицами через people зрения вместо того, чтобы вручную писать запрос, чтобы разделить данные на обеих таблицах.

Проблема Я бегу в том, что я не могу иметь NON NULL ограничение на таблицах вид отступающих в противном случае запрос типа:

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

потерпит неудачу из-за ограничения на created_at и потому NEW.create_at в функция триггера, очевидно, NULL

Так что мой вопрос: кто-нибудь знает, как обрабатывать 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

В конце концов я реализовал решение, рекомендованное Mad Scientist. Для тех, кто может наткнуться на этот вопрос в будущем мое окончательное решение было:

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 для рекомендации функции коалесценции. Это в значительной степени точное решение, которое я искал, хотя в конечном итоге я пошел с Mad Scientists, потому что я думаю, что использование значений по умолчанию для представления лучше для моих целей. – Zerodestiny

Смежные вопросы