我在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;
如果要使用PL / pgSQL的过程功能,则需要从sql
to 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;
相关回答:
一个问题是最有可能发生命名冲突。 9.0版本发生了重大变化。我引用release notes:
E.8.2.5。 PL / pgSQL的
如果变量名与查询中使用的列名冲突,PL / pgSQL现在会抛出错误(Tom Lane)
后来的版本改进了行为。在明显的位置,自动选择正确的选择。减少冲突的可能性,但它仍然存在。该建议仍适用于Postgres 9.3。