如何在PostgreSQL中构建参数化查询/视图/存储过程(或者,不情愿,Java中的函数)以支持表值参数?
我目前的工具链是带有jooq库的PostgreSQL,JDBC和Java。
某些背景。
我有一个(实际上很复杂)查询,它定义了一些统计数据的聚合处理。为简单起见,我们假设它的形式为:
create view aggregated_data as
select table1.c1, sum(table2.c2)
from table1
inner join table2 on table1.c1 = table2.c1
group by table1.c1;
我想要做的是参数化这个定义,以便我可以通过' table2'作为参数,因为我想要通过' table2'仅包含基于其他条件的行。
更明确地说,我之后的事情是:
create view aggregated_data(some_table_valued_parameter) as
select table1.c1, sum(table2.c2)
from table1
inner join (
select c1, c2 from some_table_valued_parameter
) table2 on table1.c1 = table2.c1
group by table1.c1;
如何定义某些内容,让我保留所有脚手架并只传入some_table_valued_parameter?
我考虑使用某种存储过程作为我的第一个选项,但据我所知,PostgreSQL不支持表值参数,因此可能无法实现。
第二个选项(我相信它会起作用)是使用JOOQ和Java函数动态构建查询。但这不太可取,因为数据库旨在支持登录控制台并键入SQL的人员,我也希望他们能够从脚手架中受益。
任何提示或线索都将受到赞赏。
答案 0 :(得分:2)
似乎你的主要问题是为你的存储函数设置一个表值参数,这在PostgreSQL中确实是不受支持的。但你可以使用一个记录数组,基本上是相同的更多的锅炉板(可能还有一些性能影响):
CREATE TYPE my_rec AS (
c1 BIGINT,
c2 BIGINT
);
然后:
CREATE FUNCTION my_func(almost_a_table my_rec[])
RETURNS TABLE (c1 BIGINT, c2 BIGINT)
AS $$
BEGIN
RETURN QUERY
SELECT table1.c1, sum(table2.c2)
FROM table1
INNER JOIN (
SELECT u.c1, u.c2 FROM unnest(almost_a_table) u
) table2 ON table1.c1 = table2.c1
GROUP BY table1.c1;
END
$$ LANGUAGE plpgsql;
如何使用此功能:
SELECT *
FROM my_func((
SELECT array_agg(row(t.a, t.b)::my_rec)
FROM some_table t
))
注意,既然你提到你的堆栈上有jOOQ,这种方法在使用jOOQ时也是理想的,因为jOOQ的代码生成器会为你生成所有的样板代码,这样你就可以访问来自你的jOOQ查询的my_func
也是一样的。详情如下:
http://www.jooq.org/doc/latest/manual/sql-building/table-expressions/table-valued-functions
答案 1 :(得分:1)
您不能在视图中执行此操作,但您可以创建一个PL / pgSQL函数,该函数接受表或视图名称并返回符合查询定义的记录。由于事先不知道表名,因此必须使用RETURN QUERY EXECUTE
动态执行对传入的表名的查询:
CREATE FUNCTION aggregated_data(nm name) RETURNS TABLE (c1 integer, c2 float) AS $$
BEGIN
RETURN QUERY EXECUTE
'SELECT table1.c1, sum(table2.c2) ' ||
'FROM table1 ' ||
'INNER JOIN ( ' ||
' SELECT c1, c2 FROM ' || quote_ident(nm) ||
') table2 ON table2.c1 = table1.c1 ' ||
'GROUP BY table1.c1';
END; $$ LANGUAGE plpgsql STRICT;
由于此函数返回一个关系,您可以 - 实际上应该 - 在较大查询的FROM
子句中使用此函数,就像使用视图一样:
SELECT t.*, ad.c2
FROM t
JOIN aggregated_data('relation_with_c1_and_c2_columns') ad ON ad.c1 = t.id;