1

这是我之前提出的问题的第二次迭代。我正在创建以下功能。

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 参数算作“简单变量”吗?

4

3 回答 3

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")

因为该函数被声明为“RETURNS 记录”。

但是,如果要将结果作为单独的列,则需要使用:

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);

结果将自动具有“类似表格”的结构。

于 2017-05-09T07:21:23.113 回答
1

OUT参数是可以在SELECT ... INTO语句中使用的变量。

但是,您正在混淆 SQL 函数和 PL/pgSQL 函数。

您声明函数 ( LANGUAGE 'sql') 的方式适用以下内容:

  • 它只能包含常规 SQL 语句(例如 no SELECT ... INTO),最后一条语句的结果是函数的结果(参见文档)。

  • 输出参数SELECT仅提供最后一条语句的结果列的名称。

您需要的是一个 PL/pgSQL 函数 ( LANGUAGE 'plpgsql')。

然后你可以使用SELECT ... INTO,但你必须将你的代码安排到 PL/pgSQL 块中:

[DECLARE
   <variable> <type>;
   ...]
BEGIN
   <statement>;
   ...
[EXCEPTION
    WHEN <exception> THEN
       <statement>;
       ...
    ...]
END;
于 2017-05-09T06:50:05.197 回答
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;
于 2017-05-09T06:44:14.920 回答