Postgres规则防止CTE查询

时间:2014-10-09 00:04:56

标签: postgresql postgresql-9.3

使用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)使用行级触发器之外,还有另外一种方法可以完成我试图做的事情吗?谢谢,

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语句的系统中使用某些旧数据库时可能很有用。