我想对Postgres视图的触发器进行解释。
为清楚说明我要问的问题,我将为您提供一个非常简单的案例。
在此示例中,我们有两个表(table_a
,table_b
)连接在一起,使示例(vw_table_ab
)中的视图成为一个视图。
在此示例中,我将使用琐碎的名称和简单的DDL / DML。
-- TABLE table_a
CREATE TABLE table_a
(
id serial PRIMARY KEY,
timestamp_field timestamp DEFAULT now() NOT NULL,
boolean_field boolean DEFAULT FALSE NOT NULL
);
-- TABLE table_b
CREATE TABLE table_b
(
id serial PRIMARY KEY,
timestamp_field timestamp DEFAULT now() NOT NULL,
boolean_field boolean DEFAULT FALSE NOT NULL,
id_table_a integer NOT NULL,
CONSTRAINT "fk_table_a" FOREIGN KEY (id_table_a) REFERENCES table_a (id) ON DELETE CASCADE NOT DEFERRABLE,
CONSTRAINT "u_table_a" UNIQUE (id_table_a)
);
-- VIEW vw_table_ab
CREATE VIEW vw_table_ab AS (
SELECT a.timestamp_field AS timestamp_a,
a.boolean_field AS boolean_a,
b.timestamp_field AS timestamp_b,
b.boolean_field AS boolean_b
FROM table_a a
JOIN table_b b ON a.id = b.id_table_a
);
标准动作(INSERT
,UPDATE
和DELETE
)上的触发器功能通过INSTEAD OF
触发器链接到该视图。
-- TRIGGER FUNCTION fn_trigger
CREATE FUNCTION fn_trigger() RETURNS trigger LANGUAGE plpgsql AS
$_$
DECLARE
sql TEXT;
BEGIN
sql = 'SELECT ' || TG_TABLE_NAME || '_' || lower(TG_OP) || '($1);';
IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
EXECUTE (sql) USING NEW;
RAISE NOTICE '%', sql;
RETURN NEW;
ELSE
EXECUTE (sql) USING OLD;
RAISE NOTICE '%', sql;
RETURN OLD;
END IF;
END;
$_$;
-- TRIGGER tr_table_ab
CREATE TRIGGER tr_table_ab
INSTEAD OF INSERT OR UPDATE OR DELETE ON vw_table_ab
FOR EACH ROW EXECUTE PROCEDURE fn_trigger();
我带来的示例有一个仅在插入操作上调用的触发器,执行的功能是这样的:
-- INSERT FUNCTION vw_table_ab_insert
CREATE FUNCTION vw_table_ab_insert(new vw_table_ab) RETURNS void LANGUAGE plpgsql AS
$_$
DECLARE
id_table_a integer;
BEGIN
INSERT INTO table_a (timestamp_field, boolean_field) VALUES (new.timestamp_a, new.boolean_a)
RETURNING id
INTO id_table_a;
INSERT INTO table_b (timestamp_field, boolean_field, id_table_a) VALUES (new.timestamp_a, new.boolean_b, id_table_a);
END;
$_$;
现在我们可以解决我的问题。我在视图上进行了插入,并且在触发操作时,出现了“不是违反null的行为” 错误,因为我对NOT NULL
和{{ 1}},例如:
table_a
假设先前的语句是通过编程语言框架生成的,并且我不想在后端代码中处理这种情况,但是我想在PostgreSQL的插入函数table_b
中处理这种情况。因此,在这一点上,我的问题与函数的INSERT INTO vw_table_ab (timestamp_a, boolean_a, timestamp_b, boolean_b) VALUES (now(), NULL, now(), NULL);
绑定在一起,因为我的视图字段为vw_table_ab_insert
。但是这些字段在基表的定义中有一个new
值,我想使用它。
NULL
我的问题: 如何使用表中定义的DEFAULT在视图触发中管理NULL值?
最初,我想到了将DEFAULT
放在函数中并使用...
timestamp_field timestamp DEFAULT now() NOT NULL,
boolean_field boolean DEFAULT FALSE NOT NULL
...
表达式覆盖空值,但我不是很喜欢。
例如,函数将变成这样:
IF ... THEN ...
有人可以帮助我吗?有另一种方法可以处理这种情况吗?
答案 0 :(得分:2)
最简单的方法是使用ALTER VIEW ... ALTER col SET DEFAULT
在视图上定义与基础表上的默认值相同的默认值。
然后,不插入显式NULL,而忽略INSERT
语句中的列或显式插入DEFAULT
。您产生的视图的行为就像真实表一样。