Postgres在转换时返回函数错误/失败时的空值

Yog*_*gaj 8 sql postgresql casting plpgsql

我试图将text值转换为timestamp值.对于下表称为a:

 id |         c1
----+--------------------
  1 | 03-03-2000
  2 | 01-01-2000
  3 | 12/4/1990
  4 | 12 Sept 2011
  5 | 12-1-1999 12:33:12
  6 | 24-04-89 2:33 am
Run Code Online (Sandbox Code Playgroud)

我试图select演员表演如下:

select id, c1,c1::timestampas c2 from a;

这正常工作,如果有只有前5行,但第6行地方c124-04-89 2:33 am它引发以下错误:

错误:日期/时间字段值超出范围:"24-04-89 2:33 am"
提示:也许您需要一个不同的"日期样式"设置.

我想要的是null那些不能被转换为时间戳而不是命令完全失败的值.像这样:

 id |         c1         |         c2
----+--------------------+---------------------
  1 | 03-03-2000         | 2000-03-03 00:00:00
  2 | 01-01-2000         | 2000-01-01 00:00:00
  3 | 12/4/1990          | 1990-12-04 00:00:00
  4 | 12 Sept 2011       | 2011-09-12 00:00:00
  5 | 12-1-1999 12:33:12 | 1999-12-01 12:33:12
  6 | 24-04-89 2:33 am   | (null)
(6 rows)
Run Code Online (Sandbox Code Playgroud)

编辑:
另外,有没有通用的方法来实现这个?ie :(基于klin的答案)一个plpgsql包装器函数,null它将值设置为如果它所包含的函数抛出错误.例如:一个set_null_on_error可以像这样使用的函数:

select id, c1,set_null_on_error(c1::timestamp)as c2 from a;

要么

select id, c1,set_null_on_error(to_number(c1, '99'))as c2 from a;

kli*_*lin 5

这可以通过在plpgsql函数中捕获异常来完成。

create or replace function my_to_timestamp(arg text)
returns timestamp language plpgsql
as $$
begin
    begin
        return arg::timestamp;
    exception when others then
        return null;
    end;
end $$;

select id, c1, my_to_timestamp(c1) as c2 from a;
Run Code Online (Sandbox Code Playgroud)

试图定义一个泛型函数。

假设您定义了一个函数set_null_on_error(anyelement)。呼唤

select set_null_on_error('foo'::timestamp);
Run Code Online (Sandbox Code Playgroud)

执行函数之前引发错误。

您可以尝试如下操作:

create or replace function set_null_on_error(kind text, args anyarray)
returns anyelement language plpgsql
as $$
begin
    begin
        if kind = 'timestamp' then
            return args[1]::timestamp;
        elseif kind = 'number' then
            return to_number(args[1], args[2]);
        end if;
    exception when others then 
        return null;
    end;
end; $$;

select set_null_on_error('timestamp', array['2014-01-01']);
select set_null_on_error('number', array['1.22444', '9999D99']);
Run Code Online (Sandbox Code Playgroud)

在我看来,这样的解决方案太复杂了,使用起来非常不方便,并且通常会产生难以调试的问题。