创建函数时的 Postgres 错误

Posted

技术标签:

【中文标题】创建函数时的 Postgres 错误【英文标题】:Postgres error in creating a function 【发布时间】:2014-08-14 17:20:10 【问题描述】:

我正在尝试在 Postgres 中创建一个函数,如下所示:

Create function Samplefunc() 
returns resultdata( Tested int, Score int,
       Growth int) as
$BODY$
Select 
       Count(distinct student_id) Tested, 
       Cast(Avg(R.raw_score) as Int)  Score,
       Avg(R.growth) as Growth
from results R
where R.id=1 and test_id='ME04';
$BODY$
LANGUAGE sql;

但我收到以下错误:

ERROR:  syntax error at or near "int"
LINE 2: returns resultdata( NTested int, RawScore int,
                                    ^

********** Error **********

ERROR: syntax error at or near "int"
SQL state: 42601
Character: 59

我哪里错了?

【问题讨论】:

【参考方案1】:
CREATE FUNCTION samplefunc() 
  RETURNS TABLE(ntested int, rawscore int, growth int) AS
$func$
SELECT count(DISTINCT r.student_id) -- AS NTested
      ,avg(r.raw_score)::int        -- AS RawScore
      ,avg(r.growth)::int           -- AS Growth
FROM   reports_results r
WHERE  r.test_type_id = 1
AND    r.test_id = '201403MAME04'
$func$ LANGUAGE sql;

返回表的子句是RETURNS TABLE

小心避免OUT 参数和列名之间的冲突。 (我的初稿中有这样的冲突)。表限定列以消除歧义。 RETURNS TABLE 中的所有字段名称实际上都是 OUT 参数,并且在函数内(几乎)随处可见。

还有:

avg(growth) 将导致类型与声明的返回类型 int 不匹配。你也需要投射它。使用简短的Postgres-specific syntax ::type,顺便说一句。 更好的是:返回 numeric or a floating point number 以保留平均数字中的小数位数。

列别名仅在函数内部可见。如果您不打算在函数内部引用它们,它们只是文档。

大写是怎么回事? Unquoted identifiers are cast to lower case in Postgres automatically.

如果保证查询返回单个行,您可能希望将OUT参数与RETURNS record结合起来:

CREATE FUNCTION samplefunc(OUT ntested int, OUT rawscore int, OUT growth int) 
  RETURNS record  AS ...

细微的差别:这样一来,如果没有找到任何内容,您将获得带有 NULL 值的单行,而第一个表单将不返回任何内容/没有行。

添加 IN 参数(在评论中请求)

CREATE FUNCTION samplefunc(_test_type_id int, _test_id text) 
  RETURNS TABLE(ntested int, rawscore int, growth int) AS
$func$
SELECT count(DISTINCT r.student_id)
      ,avg(r.raw_score)::int
      ,avg(r.growth)::int
FROM   reports_results r
WHERE  r.test_type_id = $1   -- or: = _test_type_id in Postgres 9.2+
AND    r.test_id = $2        -- or: = _test_id
$func$ LANGUAGE sql;

这里有很多关于 SO 的相关答案以及更多代码示例。喜欢:

PostgreSQL return a function with a Custom Data Type

Try a search.

【讨论】:

嗨..谢谢你的回答。效果很好!我如何修改它以传递一些参数,这样我就不必像“where R.test_type_id=1 and test_id='201403MAME04';”那样定义它没有了吗? @crozzfire:我为我的答案添加了另一个答案。 嗨,你能帮我吗? ***.com/questions/25814827/…【参考方案2】:

尽量不要指定复合返回类型的细节。但是,我认为回报结构必须首先存在。

Create table resultdata (NTested int, RawScore int, Growth int);

Create function Samplefunc() returns resultdata as
$BODY$
Select 
   Count(distinct student_id) as NTested, 
   Cast(Avg(R.raw_score) as Int) as RawScore,
   Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

或者尝试显式返回一个表:

Create function Samplefunc() 
    returns Table (NTested int, RawScore int, Growth int) as
$BODY$
Select 
   Count(distinct student_id) as NTested, 
   Cast(Avg(R.raw_score) as Int) as RawScore,
   Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

我认为你也可以使用输出参数返回一组记录:

Create function Samplefunc(OUT NTested int, OUT RawScore int, OUT Growth int) 
    returns SetOf Record as
$BODY$
Select 
   Count(distinct student_id) as NTested, 
   Cast(Avg(R.raw_score) as Int) as RawScore,
   Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

【讨论】:

【参考方案3】:

您正在尝试返回包含多个输出参数的记录。你应该这样做:

Create function Samplefunc(out NTested int, out RawScore int, out Growth int) as
$BODY$
Select 
       Count(distinct student_id) NTested, 
       Cast(Avg(R.raw_score) as Int)  RawScore,
       Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

您可以使用显式命名的复合类型更详细地执行相同的操作;喜欢

CREATE TYPE resultdata AS (NTested int, RawScore int, Growth int);

CREATE FUNCTION Samplefunc() RETURNS resultdata
    AS .......

或使用TABLE 之类的函数

CREATE FUNCTION Samplefunc() RETURNS TABLE(NTested int, RawScore int, Growth int)
AS
......

有关更多信息,请参阅PostgreSQL Documentation

【讨论】:

【参考方案4】:

如果您没有像 Luke 正确假设的那样定义类型“结果集”,请尝试返回一个表。

Create function Samplefunc() 
returns table( NTested int, RawScore int,
       Growth int) as
$BODY$
Select 
       Count(distinct student_id) NTested, 
       Cast(Avg(R.raw_score) as Int)  RawScore,
       Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

【讨论】:

以上是关于创建函数时的 Postgres 错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥在我的 Postgres 函数中使用 IF 语句时出现语法错误?

这个 postgres 触发函数有啥问题?

Postgres 函数确定一个区间内的周末数

Postgres:从存储函数返回结果或错误

Postgres如何创建一个在查询中使用的函数

在 Postgres 中,如何在更改表后重新验证(“类型检查”)函数和过程?