PostgreSQL generate_series () с функцией SQL в качестве аргументов - PullRequest
1 голос
/ 31 октября 2011

У меня есть функция 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);

Например, производитв следующей таблице (тип результата функции - таблица, т.е. 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

и т. д.(всего около 30 продуктов).Это история за данный месяц.

У меня также есть другой запрос, который генерирует серию месяцев:

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

Какие продукты список подобен этому:

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.

1 Ответ

2 голосов
/ 31 октября 2011

То, что вы пытаетесь сделать, может работать следующим образом:

Редактировать с дополнительной информацией

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' - это всего лишь два варианта синтаксиса, делающие то же самое.Язык plpgsql не устанавливается по умолчанию.Возможно, вам придется ввести CREATE LANGUAGE plpgsql; один раз в вашей базе данных.См. руководство здесь .

Возможно, вы могли бы упростить две ваши функции в один запрос или функцию, если хотите.

...