PostgreSQL函数/视图作用于CTE结果?

时间:2014-06-12 18:48:16

标签: sql function postgresql common-table-expression sql-function

我正在编写一个postgresql视图,它使用一些复杂的逻辑来生成数据行。它要求我对从查询两个不同表的结果派生的两组数据执行相同的一组步骤。是否可以编写一个概括这些步骤的函数?

例如:

CREATE TABLE foos (
  id bigserial primary key,
  name text not null
);

INSERT INTO foos (name) VALUES ('FOO_ONE');
INSERT INTO foos (name) VALUES ('FOO_TWO');
INSERT INTO foos (name) VALUES ('FOO_THREE');
INSERT INTO foos (name) VALUES ('FOO_FOUR');

CREATE TABLE bars (
  id bigserial primary key,
  name text not null
);

INSERT INTO bars (name) VALUES ('BAR_ONE');
INSERT INTO bars (name) VALUES ('BAR_TWO');
INSERT INTO bars (name) VALUES ('BAR_THREE');
INSERT INTO bars (name) VALUES ('BAR_FOUR');

现在我必须计算:

WITH even_foos AS (SELECT * FROM foos WHERE id % 2 = 0)
SELECT id * 2 AS double_id, name FROM even_foos;

WITH odd_bars AS (SELECT * FROM foos WHERE id % 2 = 1)
SELECT id * 2 AS double_id, name FROM odd_bars;

注意两个查询中如何重复id * 2选择。我想重用这个功能,这样我只需要实现一次这个逻辑。例如(编写语法):

WITH even_foos AS (SELECT * FROM foos WHERE id % 2 = 0)
SELECT * FROM get_double_id_and_name(even_foos);

WITH odd_bars AS (SELECT * FROM foos WHERE id % 2 = 1)
SELECT * FROM get_double_id_and_name(odd_bars);

有没有一种简单的方法可以实现这一目标?

1 个答案:

答案 0 :(得分:1)

Dynamic SQL肯定可以解决问题,因为你可以将SQL包装在一个循环中,循环在包含(0, 1)的列表上完成,然后将其动态插入到查询中获取0和1的值。

如果你想保持纯SQL,你可以将查询变成一个函数,如下所示:

CREATE FUNCTION get_foos(int) RETURNS TABLE (id bigint, name text)
    AS $$ SELECT * FROM foos WHERE id % 2 = $1 $$
    LANGUAGE SQL;

然后像这样称呼它:

SELECT get_foos(1);
SELECT get_foos(0);

对于您提供的具体示例,不清楚函数的开销是否值得,因为在这种情况下您将传递给它的值实际上只是一组2.对于一组潜在的参数值比这大得多,将公共代码分解为一个函数,正如我上面所做的那样绝对是一个巨大的胜利。 (并且考虑到你提到了一个视图,它使用一些复杂的逻辑来生成数据行,听起来它可能最终适合后一种情况,其中函数是值得的。)

当然,即使在这种情况下,将其放入函数中也是可以的,特别是如果您希望集中该逻辑。这种集中化还有将逻辑封装在数据库中的优势,因此您可以通过SQLPython程序和Ruby程序等调用它,而无需重复每种情况下实际驱动程序代码中的逻辑。

这是一个定义了函数的SQL fiddle,它被调用: http://sqlfiddle.com/#!15/fb079/3