PostgreSQL select 进入 OUT 变量
PostgreSQL select into OUT variables
这是我之前提出的问题的第二次迭代。我正在创建以下函数。
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 上的文档
...where target can be a record variable, a row variable, or a
comma-separated list of simple variables and record/row fields.
OUT 参数算作 "simple variables" 吗?
我只需更改语言并将 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;
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;
如果需要,您可以将其保留为 SQL 函数。 SQL 函数可以 return 多个 行 通过 运行 多个 SELECT 查询,但它们只能 return 多列来自相同的查询。因此,为了保留 SQL 函数,您需要使用一个 单个 查询 return 所有列。这可以通过一个常见的 table 表达式来实现:
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:
select getpogstats('foo', 1);
将 return 单行单列包含多个字段,例如:
getpogstats
-----------
(1,2,3,4,5,6,7,8,9,"2017-05-09 18:19:20")
因为函数声明为"RETURNS record"。
但是,如果您希望将结果作为单独的列,则需要使用:
select (getpogstats('foo', 1)).*;
然后您将分别获得每一列:
closehi | closelo | dayhi | ...
--------+---------+-------+----
1 | 2 | 3 | ...
通常,函数 return 超过一列的函数如果将它们声明为 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);
并且结果将自动具有 "table like" 结构。
这是我之前提出的问题的第二次迭代。我正在创建以下函数。
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 上的文档
...where target can be a record variable, a row variable, or a comma-separated list of simple variables and record/row fields.
OUT 参数算作 "simple variables" 吗?
我只需更改语言并将 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;
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;
如果需要,您可以将其保留为 SQL 函数。 SQL 函数可以 return 多个 行 通过 运行 多个 SELECT 查询,但它们只能 return 多列来自相同的查询。因此,为了保留 SQL 函数,您需要使用一个 单个 查询 return 所有列。这可以通过一个常见的 table 表达式来实现:
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:
select getpogstats('foo', 1);
将 return 单行单列包含多个字段,例如:
getpogstats
-----------
(1,2,3,4,5,6,7,8,9,"2017-05-09 18:19:20")
因为函数声明为"RETURNS record"。
但是,如果您希望将结果作为单独的列,则需要使用:
select (getpogstats('foo', 1)).*;
然后您将分别获得每一列:
closehi | closelo | dayhi | ...
--------+---------+-------+----
1 | 2 | 3 | ...
通常,函数 return 超过一列的函数如果将它们声明为 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);
并且结果将自动具有 "table like" 结构。