具有表值参数

时间:2015-05-07 02:21:29

标签: sql postgresql jooq

如何在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_pa​​rameter?

我考虑使用某种存储过程作为我的第一个选项,但据我所知,PostgreSQL不支持表值参数,因此可能无法实现。

第二个选项(我相信它会起作用)是使用JOOQ和Java函数动态构建查询。但这不太可取,因为数据库旨在支持登录控制台并键入SQL的人员,我也希望他们能够从脚手架中受益。

任何提示或线索都将受到赞赏。

2 个答案:

答案 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的代码生成器会为你生成所有的样板代码,这样你就可以访问来自你的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;