#postgresql #datetime #plpgsql #generate-series
#postgresql #datetime #plpgsql #генерировать-ряд
Вопрос:
У меня вызывается функция SQL get_forecast_history(integer,integer)
, которая принимает два аргумента, месяц и год. Функция возвращает ПОЛЬЗОВАТЕЛЬСКИЙ ТИП, созданный с помощью:
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
):
у меня фактический продукт ---- -- -------- ------ 2011 10 Продукт 1 29 2011 10 Продукт 2 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. Значение ‘2008-01-01’ не является частью серии месяцев. Это часть серии дат. Вы пытаетесь убедиться, что в ваших конечных результатах не пропущено ни одного месяца, даже если в течение этого месяца не было продуктов или фактических данных?
2. @Catcall: Хорошая мысль. Я включил строку для пустых месяцев в свое окончательное редактирование.
3. На самом деле я намеревался вернуть все месяцы в заданной серии. Пользовательская функция определяет значение, и если оно равно нулю, я все равно хочу, чтобы оно было включено.
Ответ №1:
То, что вы пытаетесь сделать, может работать следующим образом:
Редактировать с дополнительной информацией
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();
Основные моменты:
- Окончательное редактирование, чтобы включить пустую строку в течение нескольких месяцев без продуктов.
- Вы написали «ЛЕВОЕ СОЕДИНЕНИЕ», но это не так, как это может работать.
- Есть несколько способов сделать это, но
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;
один раз в вашей базе данных. Смотрите руководство здесь.
Вероятно, вы могли бы упростить свои две функции в один запрос или функцию, если хотите.
Комментарии:
1. Ошибка SQL: ОШИБКА: синтаксическая ошибка в СТРОКЕ 2 «ТАБЛИЦА» или рядом с ней: ВОЗВРАЩАЕТ ТАБЛИЦУ ( ^
2. Интересно, не поддерживается ли что-нибудь, что вы написали в 8.3?
3. Хорошо, спасибо, готов. (К сожалению, у меня нет возможности обновить, если только он не решит стать амбициозным.
4. @Pyrite: О, подождите.. версия 8.3.14 .. позвольте мне перефразировать это. Исправил мой ответ вариантом для вашей более старой версии.
5. ОШИБКА: язык «plpgsql» не существует. плачет . Позвольте мне прочитать об этом.