1

我有一个名为的 SQL 函数get_forecast_history(integer,integer),它接受两个参数,一个月和一年。该函数返回使用以下命令创建的 CUSTOM TYPE:

CREATE TYPE fcholder AS (y integer, m integer, product varchar, actual real);

函数定义的第一行是:

CREATE OR REPLACE FUNCTION get_forecast_history(integer, integer)
  RETURNS SETOF fcholder AS $$

来电:

SELECT * FROM get_forecast_history(10, 2011);

例如生成下表(函数的结果类型为表 ie SETOF):

  ym 产品实际
---- -- -------- ------
2011 10 产品1 29
2011 10 产品2 10
2011 10 产品3 8
2011 10 产品4 0
2011 10 产品5 2

等(总共约 30 种产品)。这是给定月份的历史记录。

我还有另一个生成一系列月份的查询:

SELECT to_char(DATE '2008-01-01'
            + (interval '1 month' * generate_series(0,57)), 'YYYY-MM-DD') AS ym

哪些产品列表如下:

嗯
----------
2008-01-01
2008-02-01
2008-03-01
2008-04-01
...
2011-10-01

我需要通过获取结果并将它们作为参数传递给函数来以某种方式LEFT JOIN获取generate_series上述函数的年/月组合的结果。generate_series这样,我将获得函数的结果,但对于来自generate_series. 在这一点上,我被困住了。

我正在使用 PostgreSQL 8.3.14。

4

1 回答 1

2

你试图做的事情可以这样工作:

编辑附加信息

CREATE OR REPLACE FUNCTION f_products_per_month()
  RETURNS SETOF fcholder AS
$BODY$
DECLARE
    r fcholder;
BEGIN

FOR r.y, r.m IN
    SELECT to_char(x, 'YYYY')::int4  -- AS y
          ,to_char(x, 'MM')::int4    -- AS m
    FROM  (SELECT '2008-01-01 0:0'::timestamp
        + (interval '1 month' * generate_series(0,57)) AS x) x
LOOP
    RETURN QUERY
    SELECT *    -- use '*' in this case to stay in sync
    FROM   get_forecast_history(r.m, r.y);

    IF NOT FOUND THEN
       RETURN NEXT r;
    END IF;
END LOOP;

END;
$BODY$
  LANGUAGE plpgsql;

称呼:

SELECT * FROM f_products_per_month();

要点:

  • 最终编辑以包括一个没有产品的月份的空行。
  • 你写了“LEFT JOIN”,但这不是它的工作方式。
  • 有几种方法可以做到这一点,但这RETURN QUERY是最优雅的。
  • 使用与您的函数 get_forecast_history() 使用的相同的返回类型。
  • 通过表限定列名来避免与 OUT 参数的命名冲突(在最终版本中不再适用)。
  • 不要使用DATE '2008-01-01',像我一样使用时间戳,无论如何它都必须转换为 to_char() 。更少的铸造,表现更好(在这种情况下并不重要)。
  • '2008-01-01 0:0'::timestamp并且timestamp '2008-01-01 0:0'只是两个语法变体做同样的事情。
  • 对于旧版本的 PostgreSQL,语言 plpgsql 不是默认安装的。您可能必须CREATE LANGUAGE plpgsql;在数据库中发布一次。请参阅此处的手册

如果需要,您可以将两个函数简化为一个查询或函数。

于 2011-10-31T15:32:00.227 回答