我试图在postgres中使用NVL
函数。
create or replace function nvl (anyelement, anyelement)
returns anyelement language sql as $
select coalesce(cast( $1 as decimal), cast( $2 as decimal))
$;
但是,下面的例子对我来说是失败的:
testdb=> select nvl(1,2);
ERROR: return type mismatch in function declared to return integer
DETAIL: Actual return type is numeric.
CONTEXT: SQL function "nvl" during inlining
testdb=> SELECT nvl( sum(balance), 0 ) as b FROM db.bank WHERE user = 123;
ERROR: function nvl(numeric, integer) does not exist
LINE 1: SELECT nvl( sum(balance), 0 ) as b FROM db.bank...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
当我把它改为:
create or replace function nvl (anyelement, anyelement)
returns anyelement language sql as $
select case when $1 is null then $2 else $1 END
$;
第一个示例起作用。但我仍然有失败的地方:
testdb=> SELECT nvl( sum(balance), 0 ) as b FROM db.bank WHERE user = 123;
ERROR: function nvl(numeric, integer) does not exist
LINE 1: SELECT nvl( sum(balance), 0 ) as b FROM db.bank...
希望有人能帮我解决这个问题。
发布于 2022-02-10 08:57:41
这些错误是由于对anyelement
类型的使用产生误解造成的。在文献资料中阅读:
声明为anyelement的每个位置(参数或返回值)都允许具有任何特定的实际数据类型,但在任何给定的调用中,它们都必须是相同的实际类型。
因此,您应该在表单有人提议中使用该函数:
create or replace function nvl (anyelement, anyelement)
returns anyelement language sql as $
select coalesce($1, $2)
$;
并确保实际类型的参数完全匹配。如果列balance
是数字的,那么第二个参数也必须是numeric
:
select nvl(sum(balance), 0.0)
-- or
select nvl(sum(balance), 0::numeric)
更新。“行动纲领”说:
我不能更改SQL。只调整功能。
在这种情况下,您不能使用anyelement
参数。您需要使用数值参数创建函数:
drop function if exists nvl (anyelement, anyelement);
create or replace function nvl (numeric, numeric)
returns numeric language sql as $
select coalesce($1, $2)
$;
缺点是该函数只适用于数值和/或整数参数。Postgres允许重载函数,因此您还可以为其他类型创建函数,例如:
create or replace function nvl (text, text)
returns text language sql as $
select coalesce($1, $2)
$;
https://dba.stackexchange.com/questions/307269
复制相似问题