我在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;
答案 0 :(得分:10)
如果要使用PL / pgSQL的过程功能,则需要将语言从sql
更改为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
的{{1}}表达式中。内部SELECT
中的“无行”会在表达式中生成SELECT
。作为普通SQL工作,或者您可以将其包装在 sql函数:
NULL
相关答案:
最有可能是命名冲突。 版本9.0 发生了重大变化。我引用release notes:
E.8.2.5。 PL / pgSQL的
如果变量名与a冲突,PL / pgSQL现在会抛出错误 查询中使用的列名(Tom Lane)
后来的版本改进了这种行为。在明显的位置,自动选择正确的选择。减少冲突的可能性,但它仍然存在。该建议仍适用于Postgres 9.3。