【问题标题】:Postgres plpgsql with PERFORM data-modifying CTE queries具有 PE​​RFORM 数据修改 CTE 查询的 Postgres plpgsql
【发布时间】:2017-12-08 01:44:22
【问题描述】:

我试图在下面的代码示例中模拟我的问题。在下面的代码中,我在一个过程中执行delete from test2。这很好用:

但是,在我的例子中,这个delete 是一个相当复杂的 CTE 的一部分,有几个更新和插入(没有选择,所以我添加了一个虚拟的 select 1 作为主查询)。让我们模拟一下:

with my_cte as(delete from test2) select 1

现在,我们知道,我们必须使用 perform 关键字来执行此操作:

perform (with my_cte as(delete from test2) select 1);

我收到以下错误:

ERROR: WITH clause containing a data-modifying statement must be at the top level

这是plpgsql的限制吗?

(请注意,这只是解释我的问题的一个示例。我知道这些查询没有任何意义。)

create table test
(
    key int primary key  
);

create table test2
(
    key int primary key
);

create function test() returns trigger as
$$
begin
    raise notice 'hello there';
    -- this does work
    delete from test2;
    -- this doesn't work
    perform (with my_cte as(delete from test2) select 1);
    return new;
end;
$$
language plpgsql;

create trigger test after insert on test for each row execute procedure test();

insert into test(key) select 1;

【问题讨论】:

  • postgresql.org/message-id/… 你读过上面的帖子吗?我会说这是一个限制。如果您愿意分享真正的问题会更容易 - 也许有一个更简单的解决方案,然后执行 CTW 与数据操作
  • 我使用 CTE 的原因:我确实可以有几个单独的 INSERT、DELETE、UPDATE 查询,但是在 CTE 之间传递结果并在最后返回 ...的查询。另一种方法是在 plpgsq 过程中获取数据并存储在本地数据结构中,以便在以下查询中使用它。
  • 因此,在我看来,这些查询并不是真正的useless,如您的邮件链接中所述。顺便谢谢你的链接!

标签: postgresql plpgsql common-table-expression


【解决方案1】:

您可以使用 CTE 组合多个 DELETE、INSERT、UPDATE 返回查询。而且你不需要为此执行,例如:

t=# begin; do $$ begin with d as (delete from s133 returning *) insert into s133 select * from d; raise info '%',(select count(1) from s133);
end; $$; commit;
BEGIN
Time: 0.135 ms
INFO:  4
DO
Time: 0.469 ms
COMMIT
Time: 0.887 ms
t=# select count(1) from s133;
 count
-------
     4
(1 row)

这里我删除了四行,然后在 CTE 中将它们插入回来

【讨论】:

  • 聪明。我可以将最后一个 CTE 查询移到主查询,而不是有几个 INSERT/UPDATE/DELETE CTE 和一个虚拟 select 1
【解决方案2】:

如你所见,你不能在子选择中嵌套这样的WITH 子句,你不能这样做

WITH cte AS (...)
PERFORM 1;

一种解决方案是使用SELECT ... INTO dummy 而不是PERFORM 并忽略结果。

但我不明白为什么不能在函数中使用多个 SQL 语句对 DELETEs、UPDATEs 和 INSERTs 进行编码,而不是将它们捆绑到 CTE 中。

如果您试图保护自己免受并发数据修改,请使用REPEATABLE READ 事务,以便您的所有语句都在数据库的同一快照上运行。

【讨论】:

  • 我使用 CTE 的原因:我确实可以有几个单独的 INSERTDELETEUPDATE 查询,但是在使用 @ 的 CTE 之间传递结果(更)性能更高987654332@在查询结束。另一种方法是在 plpgsq 过程中获取数据并存储在本地数据结构中,以便在以下查询中使用它。
  • 好的,然后使用SELECT 代替PERFORM 就可以了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2022-10-15
  • 1970-01-01
相关资源
最近更新 更多