作为一个例子,假设我想在postgres中编写一个安全地划分两个数字的自定义函数 - 即它应该检查其中一个参数是否为空以及除数是否为零。它应该优雅地处理这些错误条件,否则返回预期的商。
只要两个参数具有相同的数字类型(例如,两个整数,都是数字等),当前代码就可以正常工作。
CREATE OR REPLACE FUNCTION safe_divide(anyelement, anyelement) 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;
我的问题:有没有办法编写这个函数,以便我可以提供不同的数字类型?
我想避免:
在调用函数时需要显式转换参数(例如safe_divide(x::numeric, y::numeric)
)
需要为每种可能的数据类型定义函数
谢谢!
答案 0 :(得分:3)
如果使用数字参数和双精度定义函数,则可以将其用于每个数字参数。
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中的典型模式
答案 1 :(得分:0)
我担心这是不可能的:
声明为anyelement的每个位置(参数或返回值) 允许具有任何特定的实际数据类型,但在任何给定的 打电话他们必须都是相同的实际类型。 http://www.postgresql.org/docs/current/static/extend-type-system.html
我认为最好的方法是将参数投射到数字。
答案 2 :(得分:0)
我希望这也会对某人有所帮助。
感谢 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;