【问题标题】:Coalesce and Case-When with To_Date not working as expected (Postgres bug?)Coalesce 和 Case-When 与 To_Date 没有按预期工作(Postgres 错误?)
【发布时间】:2013-07-01 03:50:34
【问题描述】:

我使用的是 Postgres 9.1。 以下查询无法按预期工作。 Coalesce 应该返回第一个非空值。但是,此查询返回 null (1?) 而不是日期 (2)。

select COALESCE(
    TO_DATE('','yyyymmdd'), --(1)
    TO_DATE('20130201','yyyymmdd') --(2)
    );

--(1) this evaluates independently to null
--(2) this evaluates independently to the date,
--    and therefore is the first non-null value

我做错了什么?有什么解决方法吗?

编辑:这可能与 Coalesce 完全无关。我尝试了一些使用 Case When 构造的实验;事实证明,Postgres 有一个 丑陋的大错误,它将TO_DATE('','yyyymmdd') 视为not null,即使选择它返回 null。

[PS: 删除上面以避免误导。 Postgres 没有错误,但不会将空字符串视为 null。见答案。]

【问题讨论】:

  • 在 9.0 中,to_date('', 'yyyymmdd')0001-01-01 BC。为什么你认为to_date('', 'yyyymmdd') 应该为 NULL? documentation for to_date 在任何地方都没有提到 NULL。如果字符串没有提到模板,我找不到任何提及 to_date 所做的事情,但我只是粗略地回顾了一下。我手边没有标准的副本,所以我不知道它要说什么。
  • 另外,值得注意的是to_date('00000000', 'yyyymmdd') 也是0001-01-01 BC 所以也许missing 意味着zero
  • to_date('',...) 成为NULL 没有意义;你给它一个非空输入。如果有的话,它应该是一个错误。 “选择它”会产生非空(但仍然很糟糕)结果0001-01-01 BC。这里没有证据表明存在错误,并且从您的帖子中也不清楚您认为这个假定的错误会是什么,因为您没有定义您期望的确切行为。您是否希望 PostgreSQL 将空字符串和 null 视为同一事物?
  • @muistooshort 我没有添加“postgresql-9.1”标签,因为这个问题在 9.1 版本中似乎不是特定的(检查标签描述)。我只提到了版本,以便每个人都知道预期的语法。但无论如何 :-)
  • @ADTC 对我来说听起来像是 EMS SQL 管理器中的一个错误。在psql 中试一试,你会得到预期的结果:SELECT to_date('','yyyymmdd'); 返回0001-01-01 BC,一个有效且合理的日期。我个人认为它应该返回一个错误,但既然它没有,客户端应该接受结果。听起来您正在使用的客户端可能需要一些帮助才能理解该日期;客户端中的SELECT DATE '0001-01-01 BC'; 是做什么的?你的工具将结果转换为带有警告NULL,这有点可怕,这几乎是类似于 MySQL 的狡猾级别。

标签: sql postgresql postgresql-9.1 to-date


【解决方案1】:
SELECT TO_DATE('','yyyymmdd');

不会计算为 NULL,因为您将空字符串而不是 NULL 作为参数传递给 TO_DATE()

这将成功评估为 NULL

SELECT TO_DATE(NULL,'yyyymmdd');

如果您期望一个空字符串并希望将其视为NULL,您可以使用NULLIF()

SELECT TO_DATE(NULLIF(dt, ''),'yyyymmdd')
  FROM 
(
  SELECT CAST('' AS VARCHAR(32)) dt
) q

也就是说,您的示例代码将 (1) 评估为 NULL

SELECT COALESCE(
    TO_DATE(NULLIF('', ''),'yyyymmdd'),       --(1)
    TO_DATE(NULLIF('20130201',''),'yyyymmdd') --(2)
);

然后返回

|合并 | ---------------------------------- | 2013 年 2 月 1 日 00:00:00+0000 |

这里是SQLFiddle演示

【讨论】:

  • 但是你能证明TO_DATE('','yyyymmdd')0001-01-01 BCto_date(null, 'yyyymmdd')NULL 吗?实证结果让我内心的数据库家伙畏缩不前。
  • 好吧 to_date(null, 'yyyymmdd')NULL 恕我直言,在我能想到的任何 RDBMS 中都是完全正常和一致的。现在,Mysql 中的STR_TO_DATE('', '%Y%m%d') 也会给出恰好是0000-00-00 的零日期。 Oracle 将空字符串视为 NULL,因此 SELECT TO_DATE('') FROM dual 只给您 NULL。
  • 是的,to_datenull 应该是 null,这是理智和明智的。 to_date('',...) 返回除了错误之外的任何内容,我有点害怕;我只能假设这是为了与其他数据库兼容而做出的决定。
  • 我同意to_date(null, ...) 成为null 本身是SQL 中唯一合理的事情,但我认为'' 成为0000-00-00 没有任何理由。在争论合理的数据库行为时以 MySQL 为例正在推动它:)
  • 我发现在我的 9.1 数据库实例中,我的问题中的查询返回 null,而不是像我预期的那样返回 2 月 1 日。我想这是在 Postgres 的实现中不一致的事情之一(我发现 SQLFiddle 不是很可靠)。但是感谢NULLIF() 的提示。 有效!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-12
相关资源
最近更新 更多