2017-05-09 53 views
1

這是我先前提出的問題的第二次迭代。我正在創建以下功能。PostgreSQL選擇到OUT變量

CREATE FUNCTION public.getpogstats(IN symbol character varying, IN pogtypeid integer, OUT closehi numeric, OUT closelo numeric, OUT dayhi numeric, OUT daylo numeric, OUT s7dhi numeric, OUT s7dlo numeric, OUT t13hi numeric, OUT t13lo numeric, OUT close numeric, OUT firstdate timestamp without time zone) 
    RETURNS record 
    LANGUAGE 'sql' 

AS $function$ 
SELECT ROUND(MAX(closeprice), 2), ROUND(MIN(closeprice), 2), ROUND(MAX(dayhigh), 2), ROUND(MIN(daylow), 2), ROUND(MAX(sevendaydp), 2), ROUND(MIN(sevendaydp), 2), 
    ROUND(MAX(thirteendaydp), 2), ROUND(MIN(thirteendaydp), 2), MIN(datadate) 
    INTO closehi, closelo, dayhi, daylo, s7dhi, s7dlo, t13hi, t13lo, firstdate 
FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
WHERE symbol.symbol = symbol; 

SELECT ROUND(closeprice, 2) INTO close FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid 
WHERE datadate = (SELECT MAX(datadate) 
        FROM pogdata JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
        WHERE symbol.symbol = symbol) 
AND symbol.symbol = symbol; 

$function$; 

ALTER FUNCTION public.getpogstats(character varying, integer) 
    OWNER TO postgres; 

當我執行創建這個功能,我得到以下信息:

ERROR: syntax error at or near "," 
LINE 8:  INTO closehi, closelo, dayhi, daylo, s7dhi, s7dlo, t13hi... 
         ^
********** Error ********** 

ERROR: syntax error at or near "," 
SQL state: 42601 
Character: 620 

我試圖遵循PostgreSQL的文檔,它說

...其中目標可以是記錄變量,行變量或簡單變量和記錄/行字段的逗號分隔列表。

OUT參數計爲「簡單變量」嗎?

+1

'select ... into'只能與PL/pgSQL一起使用,而不是SQL(也是 - 不相關的 - 語言名稱是不應該放在單引號之間的標識符,所以它應該是'language sql'或'語言plpgsql') –

+0

感謝您的反饋意見。我改變了語言到「PLPGSQL」但現在的錯誤是:語法錯誤或接近「選擇」。第6行:SELECT ROUND(MAX(closeprice),2),ROUND(MIN(closeprice),2),... – KFayal

+1

您還需要更改函數的主體以符合PL/pgSQL的語法規則:https ://www.postgresql.org/docs/current/static/plpgsql.html –

回答

1

OUT參數變量,你可以在一個SELECT ... INTO語句中使用。

但是,您正在混合使用SQL函數和PL/pgSQL函數。

你聲明的函數(LANGUAGE 'sql')的方式,則按照以下規定:

  • 只能包含常規SQL語句(例如,沒有SELECT ... INTO),最後一個語句的結果是結果的功能(見the documentation)。

  • Output parameters只提供最後SELECT聲明結果列的名稱。

你需要的是一個PL/pgSQL函數(LANGUAGE 'plpgsql')。

然後你可以使用SELECT ... INTO,但你必須對你的代碼安排到PL/pgSQL的塊:

[DECLARE 
    <variable> <type>; 
    ...] 
BEGIN 
    <statement>; 
    ... 
[EXCEPTION 
    WHEN <exception> THEN 
     <statement>; 
     ... 
    ...] 
END; 
0

我只是不得不改變語言,並添加BEGIN和END包裝到以下,它都工作。那麼,它的工作到了我可以執行該程序的地步。謝謝您的幫助。

CREATE FUNCTION public.getpogstats(IN symbol character varying, IN pogtypeid integer, OUT closehi numeric, OUT closelo numeric, OUT dayhi numeric, OUT daylo numeric, OUT s7dhi numeric, OUT s7dlo numeric, OUT t13hi numeric, OUT t13lo numeric, OUT close numeric, OUT firstdate timestamp without time zone) 
    RETURNS record 
    LANGUAGE 'plpgsql' 

AS $function$ 
BEGIN 
SELECT ROUND(MAX(closeprice), 2), ROUND(MIN(closeprice), 2), ROUND(MAX(dayhigh), 2), ROUND(MIN(daylow), 2), ROUND(MAX(sevendaydp), 2), ROUND(MIN(sevendaydp), 2), 
    ROUND(MAX(thirteendaydp), 2), ROUND(MIN(thirteendaydp), 2), MIN(datadate) 
    INTO closehi, closelo, dayhi, daylo, s7dhi, s7dlo, t13hi, t13lo, firstdate 
FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
WHERE symbol.symbol = symbol; 

SELECT ROUND(closeprice, 2) INTO close FROM pogdata 
JOIN symbol ON pogdata.symbolid = symbol.symbolid 
WHERE datadate = (SELECT MAX(datadate) 
        FROM pogdata JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = pogtypeid 
        WHERE symbol.symbol = symbol) 
AND symbol.symbol = symbol; 
END; 
$function$; 

ALTER FUNCTION public.getpogstats(character varying, integer) 
    OWNER TO postgres; 
+0

另一件事:強烈建議用不同的名稱參數,然後在查詢中使用列來避免任何名稱混亂。很多人只是用'p_'來爲參數名稱加前綴。 –

1

可以保留,作爲一個SQL函數,如果你想。 SQL函數可以通過運行多個SELECT查詢返回多個,但它們只能從同一個查詢中返回多個列。因此,爲了保持SQL功能,您需要使用返回所有列的查詢單一

CREATE FUNCTION public.getpogstats(IN p_symbol character varying, IN p_pogtypeid integer, OUT closehi numeric, OUT closelo numeric, OUT dayhi numeric, OUT daylo numeric, OUT s7dhi numeric, OUT s7dlo numeric, OUT t13hi numeric, OUT t13lo numeric, OUT close numeric, OUT firstdate timestamp without time zone) 
    RETURNS record 
    LANGUAGE sql 
AS $function$ 
    with data1 as (
    SELECT ROUND(MAX(closeprice), 2) as closehi, 
      ROUND(MIN(closeprice), 2) as closelo, 
      ROUND(MAX(dayhigh), 2) as dayhi, 
      ROUND(MIN(daylow), 2) as daylo, 
      ROUND(MAX(sevendaydp), 2) as s7dhi, 
      ROUND(MIN(sevendaydp), 2) as s7dlo, 
      ROUND(MAX(thirteendaydp), 2) as t13hi, 
      ROUND(MIN(thirteendaydp), 2) as t13lo, 
      MIN(datadate) as firstdate 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
    WHERE symbol.symbol = p_symbol 
), data2 as (
    SELECT ROUND(closeprice, 2) as close 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid 
    WHERE datadate = (SELECT MAX(datadate) 
         FROM pogdata 
         JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
         WHERE symbol.symbol = p_symbol) 
    AND symbol.symbol = p_symbol 
    LIMIT 1 -- just to be sure 
) 
    select d1.closehi, d1.closelo, d1.dayhi, d1.daylo, d1.s7dhi, d1.s7dlo, d1.t13hi, d1.t13lo, d2.close, d1.firstdate 
    from data1 as d1 
    cross join data2 as d2; 

$function$; 

(我印象中這兩個查詢可以合併爲一個,但現在我不能想辦法做到這一點)


:這可以通過一個公用表表達式來實現

請注意,如果您希望獲得包含多個列的結果(而不是一列包含多個字段),則需要明確展開這些結果。

以下選擇:

select getpogstats('foo', 1); 

將返回一個單行包含多個領域,像一列:

getpogstats 
----------- 
(1,2,3,4,5,6,7,8,9,"2017-05-09 18:19:20") 

因爲函數聲明爲「收益記錄」。

但是,如果你想要的結果作爲各列,您需要使用:

select (getpogstats('foo', 1)).*; 

然後你會得到單獨的每一列:

closehi | closelo | dayhi | ... 
--------+---------+-------+---- 
     1 |  2 |  3 | ... 

通常情況下,功能恢復如果您將其聲明爲returns table (...),則多於一列更容易處理:

CREATE FUNCTION public.getpogstats(p_symbol character varying, p_pogtypeid integer) 
    returns table(closehi numeric, closelo numeric, dayhi numeric, daylo numeric, s7dhi numeric, s7dlo numeric, t13hi numeric, t13lo numeric, close numeric, firstdate timestamp without time zone) 
    LANGUAGE sql 
AS $function$ 
    with data1 as (
    SELECT ROUND(MAX(closeprice), 2) as closehi, 
      ROUND(MIN(closeprice), 2) as closelo, 
      ROUND(MAX(dayhigh), 2) as dayhi, 
      ROUND(MIN(daylow), 2) as daylo, 
      ROUND(MAX(sevendaydp), 2) as s7dhi, 
      ROUND(MIN(sevendaydp), 2) as s7dlo, 
      ROUND(MAX(thirteendaydp), 2) as t13hi, 
      ROUND(MIN(thirteendaydp), 2) as t13lo, 
      MIN(datadate) as firstdate 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
    WHERE symbol.symbol = p_symbol 
), data2 as (
    SELECT ROUND(closeprice, 2) as close 
    FROM pogdata 
     JOIN symbol ON pogdata.symbolid = symbol.symbolid 
    WHERE datadate = (SELECT MAX(datadate) 
         FROM pogdata 
         JOIN symbol ON pogdata.symbolid = symbol.symbolid AND pogdata.pogtypeid = p_pogtypeid 
         WHERE symbol.symbol = p_symbol) 
    AND symbol.symbol = p_symbol 
    LIMIT 1 -- just to be sure 
) 
    select d1.closehi, d1.closelo, d1.dayhi, d1.daylo, d1.s7dhi, d1.s7dlo, d1.t13hi, d1.t13lo, d2.close, d1.firstdate 
    from data1 as d1 
    cross join data2 as d2; 

$function$; 

然後你可以使用:

select * 
from getpogstats('foo', 1); 

,結果將自動具有結構「如表」。