普通 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 以在转换期间保留列名。
我目前正在将 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 以在转换期间保留列名。