oracle 我如何从表中替换日期中的年份

6ss1mwsb  于 2023-04-20  发布在  Oracle
关注(0)|答案(3)|浏览(179)

我想在oracle SQL developer中减去2个日期,inc_date存储为日期。我有以下代码:

select to_date(to_char(i_date,'yyyy-mm-dd'),'yyyy-mm-dd'),
       to_date(to_char('2023-') || to_char(i_date,'mm-')|| to_char(i_date,'dd-'),'yyyy-mm-dd')
       from data;

当我这样运行select时,我得到了我想要的结果,即使我减去了那2个,但即使没有减去,当我向下滚动结果时,大约250行的结果我突然得到错误消息“date not valid for month specified”.我理解错误消息,但我不明白为什么它给了我250个我想要的结果,然后错误弹出。
作为参考,我不能改变数据表本身的inc_date,我必须有2023年。简单地说,我想得到inc_date作为结果,其中每行都有2023年,但月份和日期保持不变。

7jmck4yq

7jmck4yq1#

正如@ PonderStibons所指出的,这个错误表明你的数据中有一个闰日,例如2020-02-29。你的字符串操作会试图将其转换为2023-02-29,这不是一个有效的日期。
我不明白为什么它给了我250个我想要的结果,然后错误弹出。
结果以50个为一批(SQL Developer中的默认值;您可以在首选项中更改它)。日期和字符串操作是作为提取的一部分完成的,而不是在解析查询时完成的。有问题的日期出现在碰巧在第六批中提取的行中(此时-没有order-by子句,因此当您命中它时是不确定的)。前五个是OK的,并且对于这五个提取中的每一个,您都会获得50行,因此会看到250个结果。然后当它试图获取下一个50行时,它会遇到问题日期,这会生成错误。
有多种方法可以处理或跳过有问题的日期,同时仍然进行字符串操作,包括在Oracle的最新版本中使用the to_date() call中的default ... on conversion error子句。具体执行什么取决于您希望如何处理闰日。
另一种方法是避免字符串操作,而是进行本地日期操作。您可以使用add_months,并基于原始日期中的年份与2023年之间的差异乘以12:

add_months(trunc(i_date), (2023 - extract(year from i_date)) * 12)

这将得到与大多数日期相同的结果,2020-02-29将转换为2020-02-28。
我在这里留下了trunc()来设置午夜的时间部分,正如@BarbarosÖzhan所说,你也可以在查询的第一部分使用它。
当你把它们当作减法的日期时,你真的不需要截断它们,使用这种方法,因为时间是相同的,当你减法时,你仍然会得到整数天。
fiddle
减法的一个更基本的方法是将年差乘以365;但这不能解释闰年

w51jfk4q

w51jfk4q2#

简单一点:

SQL> alter session set nls_date_format = 'dd.mm.yyyy';

Session altered.

样本数据:

SQL> WITH
  2     data (i_date)
  3     AS
  4        (SELECT DATE '2020-08-15' FROM DUAL
  5         UNION ALL
  6         SELECT DATE '2023-04-12' FROM DUAL)

查询:

7  SELECT i_date, TO_DATE ('2023-' || TO_CHAR (i_date, 'mm-dd'), 'yyyy-mm-dd') result
  8    FROM data;

I_DATE     RESULT
---------- ----------
15.08.2020 15.08.2023
12.04.2023 12.04.2023

SQL>
fgw7neuy

fgw7neuy3#

SELECT CASE
          WHEN i_date IS NULL
          THEN
             NULL
          ELSE
             TO_DATE ('2023-' || SUBSTR (TO_CHAR (i_date, 'YYYY-MM-DD'), 6),
                      'YYYY-MM-DD')
       END
  FROM DUAL;

我认为你必须处理i_date为NULL的情况。

相关问题