Postgresql 我可以编写一个自定义函数来处理不同的数值类型而不需要多个函数定义吗?

Postgresql 我可以编写一个自定义函数来处理不同的数值类型而不需要多个函数定义吗?,postgresql,sql-function,Postgresql,Sql Function,举个例子,假设我想在postgres中编写一个自定义函数,它可以安全地将两个数进行除法——也就是说,它应该检查两个参数是否为null,除数是否为零。它应该优雅地处理这些错误条件,否则将返回预期的商 只要两个参数属于相同的数值类型(例如,两个整数、两个数值等),当前代码就可以正常工作 我的问题:有没有一种方法可以编写这个函数,这样我就可以提供不同的数字类型 我想避免: 调用函数时需要显式强制转换参数(例如,safe_divide(x::numeric,y::numeric)) 需要为每个可能的数

举个例子,假设我想在postgres中编写一个自定义函数,它可以安全地将两个数进行除法——也就是说,它应该检查两个参数是否为null,除数是否为零。它应该优雅地处理这些错误条件,否则将返回预期的商

只要两个参数属于相同的数值类型(例如,两个整数、两个数值等),当前代码就可以正常工作

我的问题:有没有一种方法可以编写这个函数,这样我就可以提供不同的数字类型

我想避免:

  • 调用函数时需要显式强制转换参数(例如,
    safe_divide(x::numeric,y::numeric)

  • 需要为每个可能的数据类型定义函数


谢谢

恐怕不可能:

声明为anyelement的每个位置(参数或返回值) 允许具有任何特定的实际数据类型,但在任何给定的 调用它们必须都是相同的实际类型。


我认为最好的方法是将论点转换为数字。

恐怕这是不可能的:

声明为anyelement的每个位置(参数或返回值) 允许具有任何特定的实际数据类型,但在任何给定的 调用它们必须都是相同的实际类型。


我认为最好的方法是将参数转换为数值。

如果您使用数值参数和双精度定义函数,那么您可以对每个数值参数使用它

  CREATE OR REPLACE FUNCTION safe_divide(numeric, numeric) RETURNS numeric AS $$
   SELECT CASE 
     WHEN $1 IS NULL OR $2 IS NULL OR $2 = 0 THEN NULL ELSE $1 / $2 END;
  $$ LANGUAGE SQL;

  CREATE OR REPLACE FUNCTION safe_divide(double precision, double precision)
  RETURNS numeric AS $$
   SELECT CASE 
     WHEN $1 IS NULL OR $2 IS NULL OR $2 = 0 THEN NULL 
                                             ELSE $1::numeric / $2::numeric END;
  $$ LANGUAGE SQL;
它对其他类型的数据类型没有意义

 postgres=# select safe_divide(10::float,10::int);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

 postgres=# select safe_divide(10::numeric,10::int);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

 postgres=# select safe_divide(10::int,10::int);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

 postgres=# select safe_divide(10,10.0);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

这是PostgreSQL中的典型模式,如果使用数字参数和双精度定义函数,则可以对每个数字参数使用它

  CREATE OR REPLACE FUNCTION safe_divide(numeric, numeric) RETURNS numeric AS $$
   SELECT CASE 
     WHEN $1 IS NULL OR $2 IS NULL OR $2 = 0 THEN NULL ELSE $1 / $2 END;
  $$ LANGUAGE SQL;

  CREATE OR REPLACE FUNCTION safe_divide(double precision, double precision)
  RETURNS numeric AS $$
   SELECT CASE 
     WHEN $1 IS NULL OR $2 IS NULL OR $2 = 0 THEN NULL 
                                             ELSE $1::numeric / $2::numeric END;
  $$ LANGUAGE SQL;
它对其他类型的数据类型没有意义

 postgres=# select safe_divide(10::float,10::int);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

 postgres=# select safe_divide(10::numeric,10::int);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

 postgres=# select safe_divide(10::int,10::int);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

 postgres=# select safe_divide(10,10.0);
       safe_divide       
 ------------------------
  1.00000000000000000000
 (1 row)

这是PostgreSQL中的典型模式

我希望这也能帮助一些人

感谢Pavel Studule引导我找到这个答案

它确实会使代码干涸,但要获得覆盖,您仍然需要定义它们

在某些情况下,您可以定义包含主要工作的原始函数,然后创建调用原始函数并在函数内强制转换值的新函数定义

CREATE OR REPLACE FUNCTION last_day_in_month(dt date) RETURNS integer AS $$
BEGIN
  RETURN DATE_PART('days',
    DATE_TRUNC('month', dt)
    + '1 MONTH'::INTERVAL
    - '1 DAY'::INTERVAL
  );
END; $$
LANGUAGE PLPGSQL;

CREATE OR REPLACE FUNCTION last_day_in_month(dt timestamp) RETURNS integer AS $$
BEGIN
  RETURN last_day_in_month(dt::DATE);
END; $$
LANGUAGE PLPGSQL;

我希望这也能帮助一些人

感谢Pavel Studule引导我找到这个答案

它确实会使代码干涸,但要获得覆盖,您仍然需要定义它们

在某些情况下,您可以定义包含主要工作的原始函数,然后创建调用原始函数并在函数内强制转换值的新函数定义

CREATE OR REPLACE FUNCTION last_day_in_month(dt date) RETURNS integer AS $$
BEGIN
  RETURN DATE_PART('days',
    DATE_TRUNC('month', dt)
    + '1 MONTH'::INTERVAL
    - '1 DAY'::INTERVAL
  );
END; $$
LANGUAGE PLPGSQL;

CREATE OR REPLACE FUNCTION last_day_in_month(dt timestamp) RETURNS integer AS $$
BEGIN
  RETURN last_day_in_month(dt::DATE);
END; $$
LANGUAGE PLPGSQL;

您可以通过调用第一个定义的函数并强制转换值来干燥语句。您可以通过调用第一个定义的函数并强制转换值来干燥语句。