Postgresql

NVL 的 Postgres 函式

  • February 10, 2022

我正在嘗試NVL在 postgres 中使用。

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...
      

希望得到一些幫助來解決這個問題。

錯誤是由於對類型使用的誤解造成的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)

更新。OP 說:

我無法更改 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