普通 PostgreSQL 中 select 语句中的游标

Cursor in select statement in plain PostgreSQL

我目前正在将 Java 应用程序从 Oracle SQL 迁移到 PostgreSQL。 Oracle 版本在 select 语句中大量使用游标,如下所示:

SELECT ID, TITLE,
       CURSOR (SELECT RS.COL1, RS.COL2, RS.COL3 FROM RELATED_STUFF RS WHERE RS.ITEMID=ITEM.ID) RELATED_STUFF_ENTRIES,
       CURSOR (SELECT MRS.COL1, MRS.COL2, MRS.COL3 FROM MORE_RELATED_STUFF MRS WHERE MRS.ITEMID=ITEM.ID) MORE_RELATED_STUFF_ENTRIES
FROM ITEM;

在 Java 端,游标被简单地视为子结果集:

var relatedStuffRS = (ResultSet) rs.getObject("RELATED_STUFF_ENTRIES");

这个解决方案非常舒服,尤其是在查询游标中的许多列时,甚至在其中嵌套了第二个游标时。串联或联接将非常丑陋。

我找不到任何适用于游标的语法,文档也没有提到类似的内容。 Postgres 真的不提供这样的结构吗?如果没有,解决它的最佳方法是什么?我假设我必须编写一个“设置返回函数”来替换每个游标,但是我如何在 Java?

中查询它

这不会是直截了当或容易的(甚至 100% 等效)。

一个解决方案是创建一个接受 SQL 查询的函数,然后使用动态 SQL 和 returns refcursor。

类似于:

create or replace function cursor(p_sql text)
  returns refcursor
as
$$
declare
   l_ref refcursor;
begin
  open l_ref for execute p_sql;
  return l_ref;
end;  
$$
language plpgsql;

传递参数会很棘手,但像这样可能就足够了:

select id, title, 
       cursor(format('select rs.col1, rs.col2, rs.col3 from related_stuff rs where rs.item_id = %s', i.id)) as related_stuff_entries
from item i;

另一种选择是 return 一组(匿名)记录。可以使用 ResultSet.getArray() 检索,但您会丢失有关匿名记录中列名的元信息。

大致情况:

SELECT id, title,
       array (SELECT (rs.col1, rs.col2, rs.col3) FROM related_stuff RS WHERE rs.itemid = item.id) related_stuff_entries,
       array (SELECT (mrs.col1, mrs.col2, mrs.col3) FROM more_related_stuff mrs WHERE mrs.itemid = item.id) more_related_stuff_entries
FROM item;

请注意嵌入式查询中列列表周围的括号。他们将多列变成具有匿名记录类型的单列。

但这在 JDBC 中也很难处理。我认为 JDBC 驱动程序不支持匿名记录。


最简单的解决方案可能是 return 将嵌入结果作为 JSON 数组。在 Java 中很容易处理,但最大的缺点是您会丢失该转换的数据类型信息。

select id, title, 
       (select jsonb_agg(t) from (select rs.c1, rs.c2 from related_stuff rs where rs.item_id = i.id) t) as related
from item i;

注意嵌套派生 table 以在转换期间保留列名。