具有默认回退值的类型转换

Bru*_*uno 13 postgresql type-conversion

在 PostgreSQL (8.4) 中,我试图将字符串参数转换为 SQL 查询中的日期,然后返回到now()字符串不是有效日期(或为空)时。

在“伪SQL”中,这将是这样的:

SELECT CASE WHEN ? is not a valid date THEN now()::DATE ELSE CAST(? AS DATE) END;
Run Code Online (Sandbox Code Playgroud)

我尝试使用这两个查询来简化问题以检测空字符串:

SELECT CASE WHEN ?='' THEN now()::DATE ELSE CAST(? AS DATE) END;
SELECT DATE(CASE WHEN ?='' THEN now() ELSE ?  END);
Run Code Online (Sandbox Code Playgroud)

例如,如果参数是'',则相当于:

SELECT CASE WHEN ''='' THEN now()::DATE ELSE CAST('' AS DATE) END;
SELECT DATE(CASE WHEN ''='' THEN now() ELSE ''  END);
Run Code Online (Sandbox Code Playgroud)

两者都失败了ERROR: invalid input syntax for type timestamp with time zone: "" It 是有道理的,但这意味着ELSE无论CASE条件是否为真,都会评估块(或至少解析其类型)。以下工作,但我希望CASE(或类似)条件处理,正是当它不是有效日期时的情况。

SELECT CASE WHEN '2011-12-01'='' THEN now()::DATE ELSE CAST('2011-12-01' AS DATE) END;
Run Code Online (Sandbox Code Playgroud)

我最接近工作解决方案的是:

SELECT DATE(COALESCE(NULLIF(?, '')::timestamptz, now()));
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果参数为'',则返回当前日期,否则返回字符串参数中传递的日期(前提是可以转换为有效日期)。

我想要更进一步,将任何不能转化为DATE当前日期使用的东西。我想这可以使用自定义 PL/pgSQL 函数来完成,该函数会捕获此错误,但是可以在“普通”SQL 中(或至少使用现有的 PostgreSQL 函数)在没有这样的函数的情况下完成吗?

Jac*_*las 8

您无法像在 PL/pgSQL 中那样在 SQL 语句中处理SQL 异常

您必须按照您的建议编写自定义函数,例如:

create function is_valid_date(text) returns boolean language plpgsql immutable as $$
begin
  return case when $1::date is null then false else true end;
exception when others then
  return false;
end;$$;
Run Code Online (Sandbox Code Playgroud)

测试:

with w as (select 'asdsad'::text dt1, '2011-12-01'::text dt2, null::text dt3)
select case when is_valid_date(dt1) then dt1::date else current_date end d1,
       case when is_valid_date(dt2) then dt2::date else current_date end d2,
       case when is_valid_date(dt3) then dt3::date else current_date end d3
from w;

     d1     |     d2     |     d3
------------+------------+------------
 2011-12-06 | 2011-12-01 | 2011-12-06
Run Code Online (Sandbox Code Playgroud)