如何使用Oracle SQL从日期获取正确的ISO周号

时间:2019-01-09 14:20:16

标签: sql oracle

我尝试使用下面的代码来提取今年正确的iso周号,例如2019年7月1日使用以下代码,但它仍返回基于日历而不是基于iso的周号,即第1周而不是第2周。说实话。 NLS_TERRITORY是否设置为UK会有所不同?

to_number(to_char(to_date(date_created,'DD/MM/YYYY'),'IW')) as WEEK_PRODUCED

在此先感谢您提供的帮助。

1 个答案:

答案 0 :(得分:3)

这似乎是由于隐式日期转换-假设date_created实际上是DATE列而不是字符串。如果您的NLS设置设置为以两位数年份显示日期,例如仍为默认的'DD-Mon-RR'格式,那么您将日期值转换为字符串然后又转换回来将失去世纪。作为演示,请通过CTE提供您的日期值:

alter session set nls_date_format = 'DD-Mon-RR';

with your_table (date_created) as (
  select date '2019-01-07' from dual
)
select
  to_char(date_created) as nls_date,
  to_char(date_created, 'YYYY-MM-DD') as iso_date,
  to_char(to_date(to_char(date_created), 'DD/MM/YYYY'), 'YYYY-MM-DD') as conv_date,
  to_number(to_char(to_date(date_created,'DD/MM/YYYY'),'IW')) as WEEK_PRODUCED
from your_table;

NLS_DATE  ISO_DATE   CONV_DATE  WEEK_PRODUCED
--------- ---------- ---------- -------------
07-Jan-19 2019-01-07 0019-01-07             1

请注意,conv_date已使用NLS 2位数字年份模型转换为字符串,然后使用4位数字年份模型转换为日期,已经失去了世纪。您似乎与文字相同:

select to_char(to_date('01/07/19', 'DD/MM/YYYY'), 'YYYY-MM-DD') from dual;

TO_CHAR(TO
----------
0019-07-01

因为19岁是19年级;这里没有暗示或机制可以假设您是本世纪的意思。 (这就是RRRR格式模型的作用。)

因此,您将获得19年1月7日的ISO周编号,而不是2019年,而那一年是ISO周1。

如果您的会话使用4位数字的年份模型,那么它将起作用:

alter session set nls_date_format = 'DD/MM/YYYY';

with your_table (date_created) as (
  select date '2019-01-07' from dual
)
select
  to_char(date_created) as nls_date,
  to_char(date_created, 'YYYY-MM-DD') as iso_date,
  to_char(to_date(to_char(date_created), 'DD/MM/YYYY'), 'YYYY-MM-DD') as conv_date,
  to_number(to_char(to_date(date_created,'DD/MM/YYYY'),'IW')) as WEEK_PRODUCED
from your_table;

NLS_DATE   ISO_DATE   CONV_DATE  WEEK_PRODUCED
---------- ---------- ---------- -------------
07/01/2019 2019-01-07 2019-01-07             2

隐式生成的字符串现在具有4位数字的年份,因此将其转换回保留原始的世纪。 (当然,您还有BCE日期的问题...)

但是您根本不应该转换原始日期。只要做:

to_number(to_char(date_created,'IW')) as WEEK_PRODUCED

使用相同的CTE:

with your_table (date_created) as (
  select date '2019-01-07' from dual
)
select
  to_number(to_char(date_created,'IW')) as WEEK_PRODUCED
from your_table;

WEEK_PRODUCED
-------------
            2

无论您的NLS设置如何,它都将起作用,因为不再存在任何隐式转换。