问题
I have a SQL function called get_forecast_history(integer,integer)
that takes two arguments, a month and a year. The function returns a CUSTOM TYPE created with:
CREATE TYPE fcholder AS (y integer, m integer, product varchar, actual real);
The first line of the function definition is:
CREATE OR REPLACE FUNCTION get_forecast_history(integer, integer)
RETURNS SETOF fcholder AS $$
Calling:
SELECT * FROM get_forecast_history(10, 2011);
For example produces the following table (the result type of the function is a table i.e. SETOF
):
y m product actual ---- -- -------- ------ 2011 10 Product1 29 2011 10 Product2 10 2011 10 Product3 8 2011 10 Product4 0 2011 10 Product5 2
etc. (about 30 products total). This is the history for the given month.
I also have another query that generates a series of months:
SELECT to_char(DATE '2008-01-01'
+ (interval '1 month' * generate_series(0,57)), 'YYYY-MM-DD') AS ym
Which products a list like this:
ym ---------- 2008-01-01 2008-02-01 2008-03-01 2008-04-01 ... 2011-10-01
I need to somehow LEFT JOIN
the results of the generate_series
of year/month combinations on the function above by taking the results of the generate_series
and passing them as arguments to the function. This way I'll get the results of the function, but for every year/month combination from the generate_series
. At this point I'm stuck.
I'm using PostgreSQL 8.3.14.
回答1:
What you are trying to to could work like this:
Edit with additional info
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;
Call:
SELECT * FROM f_products_per_month();
Major points:
- Final edit to include an otherwise empty row for months without products.
- You wrote "LEFT JOIN", but that's not how it can work.
- There are several ways to do this, but RETURN QUERY is the most elegant.
- Use the same return type as your function get_forecast_history() uses.
- Avoid naming conflicts with the OUT parameters by table-qualifying the column names (not applicable any more in the final version).
- Don't use
DATE '2008-01-01'
, use a timestamp like I did, it has to be converted for to_char() anyway. Less casting, performs better (not that it matters much in this case). '2008-01-01 0:0'::timestamp
andtimestamp '2008-01-01 0:0'
are just two syntax variants doing the same.- For older versions of PostgreSQL the language plpgsql is not installed by defualt. You may have to issue
CREATE LANGUAGE plpgsql;
once in your database. See the manual here.
You could probably simplify your two functions into one query or function if you wanted.
来源:https://stackoverflow.com/questions/7955407/postgresql-generate-series-with-sql-function-as-arguments