表示我遇到的问题的简化模式如下:
CREATE TABLE a (
var1 text PRIMARY KEY
);
CREATE TABLE b (
var1 text,
var2 text PRIMARY KEY
);
CREATE TABLE c (
var1 text,
var2 text,
var3 text PRIMARY KEY
);
在表c
中,var1
和var2
分别代表表a
和b
中的键。
从这些值中,我们希望生成一个用于插入c
的新元组的键。
我们通过创建一个调用函数的触发器来实现,如下所示:
CREATE TRIGGER key_Gen
BEFORE INSERT ON c
FOR EACH ROW
EXECUTE PROCEDURE key_Gen();
CREATE FUNCTION key_Gen() RETURNS trigger AS $key_Gen$
BEGIN
-- Check that new values are not null
IF NEW.var1 IS NULL THEN
RAISE EXCEPTION 'var1 cannot be null';
END IF;
IF NEW.var2 IS NULL THEN
RAISE EXCEPTION 'var2 cannot be null';
END IF;
INSERT INTO a VALUES (NEW.var1);
INSERT INTO b VALUES (NEW.var1 || NEW.var2);
INSERT INTO c VALUES (NEW.var1 || NEW.var2 || NEW.var3);
RETURN NEW;
END;
$key_Gen$ LANGUAGE plpgsql;
a
,新密钥应为var1
。b
,新密钥应为var1
和var2
的串联。c
,新密钥应为var1
,var2
和var3
的串联。假设我插入以下内容:
INSERT INTO c VALUES ( 'TEST', 'HAS', 'PASSED');
我收到以下错误消息:
null value in column "var2" violates not-null constraint
我尝试在触发器和功能中更改各种内容,例如将BEFORE INSERT
更改为AFTER INSERT
,但这不会影响其行为。
我也尝试过参考文档和其他各种例子,但我所看到的没有一个能解决这个问题的具体情况。
我的功能甚至可以完成吗?
答案 0 :(得分:1)
你的触发器会像这样工作:
CREATE OR REPLACE FUNCTION key_gen()
RETURNS trigger AS
$func$
BEGIN
-- Check that new values are not null
IF NEW.var1 IS NULL THEN
RAISE EXCEPTION 'var1 cannot be null';
END IF;
IF NEW.var2 IS NULL THEN
RAISE EXCEPTION 'var2 cannot be null';
END IF;
INSERT INTO a(var1) VALUES (NEW.var1);
INSERT INTO b(var1, var2) VALUES (NEW.var1, NEW.var1 || NEW.var2);
NEW.var3 := (NEW.var1 || NEW.var2 || NEW.var3);
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
两个问题:
无限循环,因为您启动了另一个INSERT INTO c ...
。只需指定NEW.var3
。
您的INSERT
语句通常应该包含持久语句的目标列表!
那么你就不会错过b
的非法声明,你无意中指派var1
并将pk列保留为NULL。
但我会不鼓励使用此设计。
删除触发器并将此查询与data-modifying CTEs一起使用。你要求的一切都是:
WITH val AS (
SELECT 'TEST'::text AS v1 -- insert values once
,'HAS'::text AS v2
,'PASSED'::text AS v3
)
, ins AS (
SELECT v1 AS var1
,v1 || v2 AS var2
,v1 || v2 || v3 AS var3
FROM val
WHERE v1 IS NOT NULL
AND v2 IS NOT NULL
AND v3 IS NOT NULL
)
, a AS (INSERT INTO a(var1) SELECT var1 FROM ins)
, b AS (INSERT INTO b(var1, var2) SELECT var1, var2 FROM ins)
INSERT INTO c(var1, var2, var3) SELECT var1, var2, var3 FROM ins
RETURNING *;
最终的RETURNING子句是可选的。
此相关答案中的更多解释,链接和详细信息:
INSERT rows into multiple tables in a single query, selecting from an involved table
如果需要,您可以轻松地将其包装到SQL函数中:
CREATE OR REPLACE function f_tripple_ins(v1 text, v2 text, v3 text)
RETURNS void AS
$func$
WITH ins AS (
SELECT v1 AS var1
,v1 || v2 AS var2
,v1 || v2 || v3 AS var3
WHERE v1 IS NOT NULL
AND v2 IS NOT NULL
AND v3 IS NOT NULL
)
, a AS (INSERT INTO a(var1) SELECT var1 FROM ins)
, b AS (INSERT INTO b(var1, var2) SELECT var1, var2 FROM ins)
INSERT INTO c(var1, var2, var3) SELECT var1, var2, var3 FROM ins
$func$ LANGUAGE sql;
适用于Postgres 9.2或更高版本。
在Postgres 9.1或更早版本中,您必须使用$1
,$2
,$3
来引用SQL函数中的输入参数。
答案 1 :(得分:0)
插入部件不应该如下所示:
INSERT INTO a VALUES (NEW.var1);
INSERT INTO b VALUES (NEW.var1, New.var1 || NEW.var2);
INSERT INTO c VALUES (NEW.var1, NEW.var2, NEW.var1 || NEW.var2 || NEW.var3);