【问题标题】:Postgres Rules Preventing CTE Queries防止 CTE 查询的 Postgres 规则
【发布时间】:2014-10-09 00:04:55
【问题描述】:

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

【问题讨论】:

  • 为什么不想使用触发器?
  • 我的数据库经验只有大约 5 个月,所以每当我遇到一个我无法找到我真正喜欢的解决方案的问题时,我想我应该请教专家,这样我才能了解各种选择。对于这么简单的事情,出于性能原因,一条规则似乎是可行的方法,但我不喜欢无法在查询中使用可写 CTE 的限制。
  • 我应该补充一点,我计划使用行级触发器作为首选解决方案,除非有人在 SO 提供更好的选择。
  • 仅供参考:来源可以在src/backend/rewrite/rewriteHandler.c中找到

标签: postgresql postgresql-9.3


【解决方案1】:

TL;DR:使用触发器,而不是规则。

一般来说,触发器优先于规则,除非规则是绝对必要的。 (实际上,它们从来都不是。)

使用规则会引入大量问题,这些问题会使您的生活变得不必要地复杂化。你在这里遇到了一个。另一个(主要)例如,受影响的行数将对应于最后一个查询的行数 - 如果您在某处依赖 FOUND 并且您的查询错误地报告没有行受到查询的影响,你会遇到痛苦的错误。

此外,偶尔有人说要彻底弃用 Postgres 规则:

http://postgresql.nabble.com/Deprecating-RULES-td5727689.html

【讨论】:

    【解决方案2】:

    作为另一个答案,我绝对建议在规则之前使用 INSTEAD OF 触发器。

    但是,如果由于某种原因您不想更改现有的 VIEW RULE 并且仍想使用 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 包装语句的系统使用一些遗留数据库时,这可能很有用。

    【讨论】:

      猜你喜欢
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 2013-01-31
      • 1970-01-01
      • 1970-01-01
      • 2022-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多