【问题标题】:CASE and TO_DATE in OracleOracle 中的 CASE 和 TO_DATE
【发布时间】:2020-06-29 08:04:49
【问题描述】:

我对 Oracle 中的 CASE 有疑问。 例如,我有一个包含两列的表,并希望根据这两列创建第三列。

第一列包含天和月的组合,存储为 NUMBER,例如2305 --> 5 月 23 日、503 --> 3 月 5 日等。这些值都是有效日期或 NULL。第二列有年份(存储为 NUMBER,NOT NULL),例如2019 年,2018 年。 我现在想从这两个列中创建一个 DATE 列,这样如果第一列中的值为 NULL,那么新列应该为 NULL,否则第一列和第二列的串联作为 DATE . 例如

day   year       result
2305  2018   --> 23/05/2018
505   2019   --> 05/05/2019
NULL  2020   --> NULL

我试过了:

CASE WHEN day IS NOT NULL THEN TO_DATE (LPAD (TO_CHAR (day || year), 8, '0'), 'dd/mm/yyyy') ELSE NULL END AS date

但它会抛出错误“ORA-01847 day of month must be between 1 and last day of month”。

我在 Stack Overflow 上搜索并发现有时,在检查 WHEN 条件之前评估 CASE 语句中的“THEN”表达式。这可能是问题所在,因为当 day 为 NULL 时,LPAD 给出的结果不能转换为 DATE。有没有办法绕过这个?理想情况下,我想要一些命令告诉 Oracle 首先检查 day 是否为 NULL,然后仅在不为 NULL 时评估结果。还是有其他方法可以解决我的问题?

最好的问候。

【问题讨论】:

  • 您发布的代码得到 ORA-00907。如果您只是在year 之后添加),那么它就可以工作(尽管to_char() 是多余的)。该错误表明您正在进行隐式转换,但如果不查看实际代码,则很难准确判断位置。
  • @AlexPoole 仔细查看使用的格式掩码,然后与输入TO_DATE 的实际文本数据进行比较。实际上,我的回答也可能是省略了以某种方式格式化日期的步骤。
  • @Tim - Oracle doesn't error on that by default - 这通常更像是诅咒而不是祝福......即使使用 FX 也是错误的错误。
  • @AlexPoole:对不起,我忘记了(在这个问题中)一年后的“)”。但是使用“)”它对我不起作用。我现在编辑了。
  • @user13832956 - 但这有效in db<>fiddle。因此,您的代码仍然不同,或者您有其他无效数据 - 例如少于 3 位数的一天。

标签: sql oracle


【解决方案1】:

请使用以下查询,

使用LPAD()

select  case when day is null then null else to_char(to_date(lpad(date1, 4, 0)||year1, 'ddMMyyyy'), 'dd/MM/YYYY') as result from table;

LPAD 示例:

select to_char(to_date(lpad(date1, 4, 0)||year1, 'ddMMyyyy'), 'dd/MM/YYYY') from
(select '505' as date1, 2019 as year1 from dual
union all
select '2305' as date1, 2018 as year1 from dual);

使用CASE

select case when day is null then null else 
to_date((case when length(day) = 3 then '0'||ltrim(rtrim(day)) else ltrim(rtrim(day)) 
end)||ltrim(rtrim(year)), 'ddMMyyyy') end as result 
from table;

CASE 示例:

select to_date((case when length('505') = 3 then '0'||ltrim(rtrim('505')) else ltrim(rtrim('505')) end)||'2019', 'ddMMyyyy') as result from dual;
select to_date('2305'||'2019', 'ddMMyyyy') as result from dual;  

【讨论】:

  • 真的可以用day = null吗?
  • 我的错,使用日为空。编辑查询
  • lpad 是在连接日期和年份后应用的,因此 505 和 2019 将变为 05052019 - 看起来不错?
  • 是的,使用 lpad 为您提供更多查询
  • 使用 LPAD 和 CASE 提供
【解决方案2】:

如果您想走这条路,您应该首先使用TO_CHARdayyear 字段转换为文本,然后将day 左填充最多一个零,最后调用TO_DATE关于这两个字段之间的连接:

SELECT
    day,
    year,
    CASE WHEN day IS NOT NULL
         THEN TO_DATE(LPAD(TO_CHAR(day), 4, '0') || TO_CHAR(year), 'ddmmyyyy') END AS "date"
FROM yourTable;

Demo

但请注意,如果您只保留一个适当的日期列来存储您的日期信息,那么您的生活会轻松得多

【讨论】:

  • 关于您的注释:不幸的是,这不是我的选择——该值存储在一个列中,其中也有适当的 NUMBER(并从那里提取)。
  • 我收到了与您之前收到的相同的错误(在我的代码中,我选择了更多的列,然后只选择了这三列——这可能是个问题吗?)。
  • 那么我的猜测是您还有其他数据,实际上并未包含在您的问题中,这破坏了我的答案中的代码。我的回答对您向我们展示的数据有效。
  • 嗯,你能解释一下什么样的数据会破坏代码吗?您是指日期和年份列中的数据还是其他内容?
  • @user13832956 - 两位数的日期值,例如12 所以当填充它变成 0012 时,它给出 DD 00,这是非法的。否则 3106 将是 6 月份的非法 DD。这就是为什么您应该使用正确的日期数据类型,以避免这种不良数据。
猜你喜欢
  • 1970-01-01
  • 2011-10-27
  • 1970-01-01
  • 2018-06-17
  • 2017-04-11
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多