带有 PERFORM 数据修改 CTE 查询的 Postgres plpgsql
Postgres plpgsql with PERFORM data-modifying CTE queries
我试图在下面的代码示例中模拟我的问题。在下面的代码中,我在一个过程中执行 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;
如您所见,您既不能在子选择中嵌套这样的 WITH
子句,也不能
WITH cte AS (...)
PERFORM 1;
一种解决方案是使用 SELECT ... INTO dummy
而不是 PERFORM
并忽略结果。
但我不明白为什么你不能在你的函数中使用多个 SQL 语句而不是捆绑来编写 DELETE
s、UPDATE
s 和 INSERT
s他们进入 CTE。
如果您试图保护自己免受并发数据修改,请使用 REPEATABLE READ
事务,以便您的所有语句都对数据库的同一个快照进行操作。
您可以使用 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 中将它们插入回来
我试图在下面的代码示例中模拟我的问题。在下面的代码中,我在一个过程中执行 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;
如您所见,您既不能在子选择中嵌套这样的 WITH
子句,也不能
WITH cte AS (...)
PERFORM 1;
一种解决方案是使用 SELECT ... INTO dummy
而不是 PERFORM
并忽略结果。
但我不明白为什么你不能在你的函数中使用多个 SQL 语句而不是捆绑来编写 DELETE
s、UPDATE
s 和 INSERT
s他们进入 CTE。
如果您试图保护自己免受并发数据修改,请使用 REPEATABLE READ
事务,以便您的所有语句都对数据库的同一个快照进行操作。
您可以使用 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 中将它们插入回来