设置Postgres函数的默认返回值

问题描述 投票:4回答:1

我在Postgres中有以下功能:

CREATE OR REPLACE FUNCTION point_total(user_id integer, gametime date)
  RETURNS bigint AS
$BODY$
SELECT sum(points) AS result
  FROM picks
 WHERE user_id = $1
   AND picks.gametime > $2
   AND points IS NOT NULL;
$BODY$
  LANGUAGE sql VOLATILE; 

它工作正常,但是当用户启动并且没有点时,它会非常合理地返回NULL。如何修改它以使其返回0。

将函数体更改为下面的结果会导致“错误:语法错误在或接近”IF“。

SELECT sum(points) AS result
  FROM picks
 WHERE user_id = $1
   AND picks.gametime > $2
   AND points IS NOT NULL;

IF result IS NULL
   SELECT 0 AS result;
END;
sql function postgresql if-statement plpgsql
1个回答
10
投票

如果要使用PL / pgSQL的过程功能,则需要从sqlto plpgsql更改语言。功能体也会改变。

请注意,所有参数名称在函数体中都是可见的,包括所有级别的SQL语句。如果您创建命名冲突,则可能需要对列名进行表限定,如下所示:table.col,以避免混淆。既然您通过位置参考($n)引用函数参数,我只是删除了参数名称以使其工作。

最后,在THEN声明中缺少IF - 错误消息的直接原因。

人们可以使用COALESCE来代替NULL值。但这仅在至少有一个结果行时才有效。 COALESCE无法修复“没有行”它只能取代实际的NULL值。

有几种方法可以涵盖所有NULL病例。在plpgsql函数中:

CREATE OR REPLACE FUNCTION point_total(integer, date, OUT result bigint)
  RETURNS bigint AS
$func$
BEGIN

SELECT sum(p.points)          -- COALESCE would make sense ...
INTO   result
FROM   picks p
WHERE  p.user_id = $1
AND    p.gametime > $2
AND    p.points IS NOT NULL;  -- ... if NULL values were not ruled out

IF NOT FOUND THEN             -- If no row was found ...
   result := 0;               -- ... set to 0 explicitly
END IF;

END
$func$  LANGUAGE plpgsql;

或者您可以将整个查询括在外部COALESCE中的SELECT表达式中。内部SELECT的“无行”导致表达式中的NULL。作为普通SQL工作,或者您可以将其包装在sql函数中:

CREATE OR REPLACE FUNCTION point_total(integer, date)
  RETURNS bigint AS
$func$
SELECT COALESCE(
  (SELECT sum(p.points)
   FROM   picks p
   WHERE  p.user_id = $1
   AND    p.gametime > $2
   -- AND    p.points IS NOT NULL  -- redundant here
  ), 0)
$func$  LANGUAGE sql;

相关回答:

Concerning naming conflicts

一个问题是最有可能发生命名冲突。 9.0版本发生了重大变化。我引用release notes

E.8.2.5。 PL / pgSQL的

如果变量名与查询中使用的列名冲突,PL / pgSQL现在会抛出错误(Tom Lane)

后来的版本改进了行为。在明显的位置,自动选择正确的选择。减少冲突的可能性,但它仍然存在。该建议仍适用于Postgres 9.3。

© www.soinside.com 2019 - 2024. All rights reserved.