使用Postgres 9.3:
我试图在另一个表上执行插入时自动填充表。这似乎是一个很好的规则使用,但在将规则添加到第一个表后,我不再能够使用可写CTE执行插入第二个表。这是一个例子:
CREATE TABLE foo (
id INT PRIMARY KEY
);
CREATE TABLE bar (
id INT PRIMARY KEY REFERENCES foo
);
CREATE RULE insertFoo AS ON INSERT TO foo DO INSERT INTO bar VALUES (NEW.id);
WITH a AS (SELECT * FROM (VALUES (1), (2)) b)
INSERT INTO foo SELECT * FROM a
运行此操作时,我收到错误
“错误:WITH不能在由规则重写的查询中使用 多个查询“。
我搜索过该错误字符串,但我只能找到源代码的链接。我知道我可以使用行级触发器执行上述操作,但似乎我应该能够在语句级别执行此操作。为什么我不能使用可写的CTE,当这样的查询(在这种情况下)可以很容易地重写为:
INSERT INTO foo SELECT * FROM (VALUES (1), (2)) a
有没有人知道除了1)使用规则阻止使用“with”查询或2)使用行级触发器之外,还有另外一种方法可以完成我试图做的事情吗?谢谢,
答案 0 :(得分:3)
TL; DR:使用触发器,而不是规则。
一般来说,除非规则是绝对必要的,否则更喜欢触发规则。 (实际上,它们从来都不是。)
使用规则会引入大量问题,这些问题将使您的生活不必要地复杂化。你在这里碰到了一个。例如,另一个(主要)是受影响的行数将与最后一个查询的行数相对应 - 如果您依赖于某处的FOUND并且您的查询错误地报告没有行受到查询的影响,你会陷入痛苦的错误。
此外,偶尔会有人直接贬低Postgres规则:
http://postgresql.nabble.com/Deprecating-RULES-td5727689.html
答案 1 :(得分:1)
作为另一个答案,我绝对建议在规则之前使用INSTEAD OF触发器。
但是,如果由于某种原因您不想更改现有的VIEW规则而仍然希望与WITH一起使用,则可以通过将VIEW包装在存储过程中来实现:
create function insert_foo(int) returns void as $$
insert into foo values ($1)
$$ language sql;
WITH a AS (SELECT * FROM (VALUES (1), (2)) b)
SELECT insert_foo(a.column1) from a;
这在通过某些带有CTE语句的系统中使用某些旧数据库时可能很有用。