【发布时间】:2021-11-26 12:04:02
【问题描述】:
当我使用 Microsoft SQL Server 数据库时,我有时会从存储过程返回多个结果集。我经常返回这么多,以至于很难理解哪个是哪个。为了解决这个问题,我遵循从同事那里学到的约定:第一个结果集是一个“地图”,它定义了第二个和其他结果集的名称。它有一条记录,其中每个字段名称是结果集的名称,相应的字段值是它在返回的结果集数组中的索引。客户端代码通过首先按名称查找索引来访问特定的结果集。
下面的简单例子展示了这个想法:
create or alter procedure divide
@a int,
@b int
as
begin
declare
@error int = 0
-- Name-to-index map
select
1 as result,
2 as error
-- Result
if @b = 0
begin
set @error = 1
select
null as result
end
else
begin
select
@a / @b as result
end
-- Error
select
@error as error
end
在此示例中,第一个结果集(索引:0)给出了另外 2 个结果集:一个称为“结果”(索引:1),另一个称为“错误”(索引:2)。两者都只包含一条记录:分别是除法的结果和错误代码。
示例调用 #1:
exec divide @a = 91, @b = 13
JSON 格式的结果集:
[
[{ result: 1, error: 2 }],
[{ result: 7 }],
[{ error: 0 }]
]
示例调用 #2:
exec divide @a = 91, @b = 0
JSON 格式的结果集:
[
[{ result: 1, error: 2 }],
[{ result: null }],
[{ error: 1 }]
]
我尝试使用官方文档,尤其是 this page 将这种技术移植到 PostgreSQL 14。我想出了这个:
create or replace function divide(
a integer,
b integer
)
returns setof refcursor
language sql as
$$
declare
ref1 refcursor;
ref2 refcursor;
ref3 refcursor;
error int := 0;
begin
-- Name-to-index map
open ref1 for select
1 as result,
2 as error;
return next ref1;
-- Result
if b = 0 then
error := 1;
open ref2 for select
null as result;
else
open ref2 for select
a / b as result;
end if;
return next ref2;
-- Error
open ref3 for select
error;
return next ref3;
end;
$$;
不幸的是,我收到一个错误:syntax error at or near "refcursor",指的是declare 之后第一行中的refcursor。
【问题讨论】:
-
在 Postgres 中模仿 SQL Server 方法会给您带来很多麻烦——尤其是当过程被(错误)用于返回任意和多个结果时。 Postgres 的工作方式不同。省去很多麻烦,只需运行三个查询并将它们与 UNION ALL 或任何适合您的东西放在一起。然后创建一个返回表的函数。
-
@a_horse_with_no_name 我返回的结果集是逻辑连接的(例如显示在同一个网页上),但结构不同。通过在单个函数调用中返回所有内容,我想利用 Postgres 函数在事务中运行,因此结果将为我提供一组一致的数据。如果我在没有事务的情况下使用多个选择,并且我的选择之间有更新,我可能会得到不一致的结果。 (我希望我不会误解这里的基本内容——我不是数据库专家。)
-
我不完全确定过程或函数中的所有查询都看到相同的快照。我希望您仍然可以得到不一致的结果。保证一致性的唯一方法是使用
repeatable read或serializable隔离级别运行所有查询。 -
@a_horse_with_no_name 嗯...看起来 PostgreSQL 中的默认隔离级别只有
read committed。此外,与 MS SQL 版本相反,Postgres 函数只返回游标,所以我必须在事务中自己获取记录。 -
read committed仅保证单个语句的一致结果,而不是事务。正如我所写的:我怀疑一个过程中的所有查询都被认为是一个单一的语句——但有一些人比我更了解它的内部结构。我只是猜测
标签: postgresql ref-cursor multiple-resultsets postgresql-14