Oracle SQL:如何将日期间隔添加到日期?

问题描述 投票:0回答:4

我想将日期间隔添加到 Oracle SQL 中的日期列表,即下周的星期一。但是,当我使用建议的

date + 1
类型的间隔时,我遇到了一个非常奇怪的错误,其中只有一天按预期加起来,即
Wednesday
。我在这里做错了什么?这是 Oracle SQL Developer 中的错误吗?

WITH data AS (
    SELECT '29-JAN-23' dt FROM dual UNION
    SELECT '30-JAN-23' dt FROM dual UNION
    SELECT '31-JAN-23' dt FROM dual UNION
    SELECT '01-FEB-23' dt FROM dual UNION
    SELECT '02-FEB-23' dt FROM dual UNION
    SELECT '03-FEB-23' dt FROM dual UNION
    SELECT '04-FEB-23' dt FROM dual UNION
    SELECT '05-FEB-23' dt FROM dual UNION
    SELECT '06-FEB-23' dt FROM dual UNION
    SELECT '07-FEB-23' dt FROM dual UNION
    SELECT '08-FEB-23' dt FROM dual UNION
    SELECT '09-FEB-23' dt FROM dual
)

SELECT
    TO_DATE(dt) dt,
    TO_CHAR(TO_DATE(dt),'DAY') dt_day,
    CASE
        WHEN TO_CHAR(TO_DATE(dt),'DAY') = 'MONDAY'      THEN TO_DATE(dt)
        WHEN TO_CHAR(TO_DATE(dt),'DAY') = 'TUSEDAY'     THEN TO_DATE(dt) + 6
        WHEN TO_CHAR(TO_DATE(dt),'DAY') = 'WEDNESDAY'   THEN TO_DATE(dt) + 5
        WHEN TO_CHAR(TO_DATE(dt),'DAY') = 'THURSDAY'    THEN TO_DATE(dt) + 4
        WHEN TO_CHAR(TO_DATE(dt),'DAY') = 'FRIDAY'      THEN TO_DATE(dt) + 3
        WHEN TO_CHAR(TO_DATE(dt),'DAY') = 'SATURDAY'    THEN TO_DATE(dt) + 2
        WHEN TO_CHAR(TO_DATE(dt),'DAY') = 'SUNDAY'      THEN TO_DATE(dt) + 1
    END new_dt
FROM data
ORDER BY TO_DATE(dt)
;

输出

| DT        | DT_DAY    | NEW_DT    |
|-----------|-----------|-----------|
| 29-JAN-23 | SUNDAY    |           |
| 30-JAN-23 | MONDAY    |           |
| 31-JAN-23 | TUESDAY   |           |
| 01-FEB-23 | WEDNESDAY | 06-FEB-23 |
| 02-FEB-23 | THURSDAY  |           |
| 03-FEB-23 | FRIDAY    |           |
| 04-FEB-23 | SATURDAY  |           |
| 05-FEB-23 | SUNDAY    |           |
| 06-FEB-23 | MONDAY    |           |
| 07-FEB-23 | TUESDAY   |           |
| 08-FEB-23 | WEDNESDAY | 13-FEB-23 |
| 09-FEB-23 | THURSDAY  |           |
sql oracle oracle-sqldeveloper intervals
4个回答
2
投票

几件事:为 to_date 使用格式掩码,然后记住 'DAY' 返回一个字符串,该字符串填充了一定长度的空格。 因此:

WITH data AS (
SELECT '29-JAN-23' dt FROM dual UNION
SELECT '30-JAN-23' dt FROM dual UNION
SELECT '31-JAN-23' dt FROM dual UNION
SELECT '01-FEB-23' dt FROM dual UNION
SELECT '02-FEB-23' dt FROM dual UNION
SELECT '03-FEB-23' dt FROM dual UNION
SELECT '04-FEB-23' dt FROM dual UNION
SELECT '05-FEB-23' dt FROM dual UNION
SELECT '06-FEB-23' dt FROM dual UNION
SELECT '07-FEB-23' dt FROM dual UNION
SELECT '08-FEB-23' dt FROM dual UNION
SELECT '09-FEB-23' dt FROM dual

)

SELECT
    TO_DATE(dt) dt,
    TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY') dt_day,
    CASE
        WHEN trim(TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY')) = 'MONDAY'      THEN TO_DATE(dt,'dd-mon-rr')
        WHEN trim(TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY')) = 'TUSEDAY'     THEN TO_DATE(dt,'dd-mon-rr') + 6
        WHEN trim(TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY')) = 'WEDNESDAY'   THEN TO_DATE(dt,'dd-mon-rr') + 5
        WHEN trim(TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY')) = 'THURSDAY'    THEN TO_DATE(dt,'dd-mon-rr') + 4
        WHEN trim(TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY')) = 'FRIDAY'      THEN TO_DATE(dt,'dd-mon-rr') + 3
        WHEN trim(TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY')) = 'SATURDAY'    THEN TO_DATE(dt,'dd-mon-rr') + 2
        WHEN trim(TO_CHAR(TO_DATE(dt,'dd-mon-rr'),'DAY')) = 'SUNDAY'      THEN TO_DATE(dt,'dd-mon-rr') + 1
    END new_dt
FROM data
ORDER BY TO_DATE(dt,'dd-mon-rr')
;

2
投票

您的转换可以简化为:

TRUNC(<original_date> + 6,'IW')

IW
format 元素 是 ISO 日历周,它始终从星期一开始,并截断为该周的每一天提供相同的周开始日期;基本上从星期二开始为您添加六个调整。

所以首先将您的字符串转换为日期:

TRUNC(TO_DATE(dt,'dd-mon-rr','nls_date_language=english') + 6,'IW')

(当然,并不是说您应该将日期存储为字符串;它们在您的示例数据 CTE 中,但可能会检查您真正使用的数据类型,并且您不只是假设您需要转换,因为您 在您的客户端中查看该格式的实际日期...)

使用您当前的 CTE 得到相同的结果:

SELECT
    TO_DATE(dt) dt,
    TO_CHAR(TO_DATE(dt,'dd-mon-rr','nls_date_language=english'),'FMDAY','nls_date_language=english') dt_day,
    TRUNC(TO_DATE(dt,'dd-mon-rr','nls_date_language=english') + 6,'IW') new_dt
FROM data
ORDER BY TO_DATE(dt,'dd-mon-rr','nls_date_language=english')
;
DT DT_DAY NEW_DT
29-JAN-23 周日 23 年 1 月 30 日
23 年 1 月 30 日 星期一 23 年 1 月 30 日
31-JAN-23 星期二 06-FEB-23
01-FEB-23 星期三 06-FEB-23
02-FEB-23 星期四 06-FEB-23
03-FEB-23 星期五 06-FEB-23
04-FEB-23 星期六 06-FEB-23
05-FEB-23 周日 06-FEB-23
06-FEB-23 星期一 06-FEB-23
07-FEB-23 星期二 13-FEB-23
08-FEB-23 星期三 13-FEB-23
09-FEB-23 星期四 13-FEB-23

小提琴

我已经将可选的第三个参数包含在

to_date()
中,因此即使会话日期语言是其他语言,月份缩写也会被识别。如果您从实际日期而不是字符串开始,则无需担心另一件事。


1
投票

您可以将生成器简化为:

WITH data (dt) AS (
  SELECT DATE '2023-01-29' + LEVEL - 1
  FROM   DUAL
  CONNECT BY DATE '2023-01-29' + LEVEL - 1 <= DATE '2023-02-09'
)
SELECT dt,
       TO_CHAR(dt,'fmDAY') dt_day,
       CASE
       WHEN dt = TRUNC(dt, 'IW')
       THEN dt 
       ELSE TRUNC(dt, 'IW') + 7
       END new_dt
FROM   data
ORDER BY dt;

哪些输出:

DT DT_DAY NEW_DT
2023-01-29 00:00:00 周日 2023-01-30 00:00:00
2023-01-30 00:00:00 星期一 2023-01-30 00:00:00
2023-01-31 00:00:00 星期二 2023-02-06 00:00:00
2023-02-01 00:00:00 星期三 2023-02-06 00:00:00
2023-02-02 00:00:00 星期四 2023-02-06 00:00:00
2023-02-03 00:00:00 星期五 2023-02-06 00:00:00
2023-02-04 00:00:00 星期六 2023-02-06 00:00:00
2023-02-05 00:00:00 周日 2023-02-06 00:00:00
2023-02-06 00:00:00 星期一 2023-02-06 00:00:00
2023-02-07 00:00:00 星期二 2023-02-13 00:00:00
2023-02-08 00:00:00 星期三 2023-02-13 00:00:00
2023-02-09 00:00:00 星期四 2023-02-13 00:00:00

小提琴

我在这里做错了什么?

TO_DATE(date_value, 'DAY')
输出一个固定长度的字符串,它是您的语言中最长日期名称的长度。对于英语是
'WEDNESDAY'
和其他字符串将用空格填充,例如
'MONDAY   '
.

如果你不想填充字符串,那么使用

TO_DATE(date_value, 'fmDAY')
然后你的代码将工作(如果你拼写
TUESDAY
正确并且隐式日期转换成功)。

小提琴


0
投票

oracle 有一个简单的版本来获取日期

select date'2023-01-29' + level - 1 dt
from   dual
connect by level <= (
  date'2023-02-15' - date'2023-01-29' + 1
);

DT
29-JAN-23
23 年 1 月 30 日
31-JAN-23
01-FEB-23
02-FEB-23
03-FEB-23
04-FEB-23
05-FEB-23
06-FEB-23
07-FEB-23
08-FEB-23
09-FEB-23
10-FEB-23
11-FEB-23
12-FEB-23
13-FEB-23
14-FEB-23
15-FEB-23

小提琴

© www.soinside.com 2019 - 2024. All rights reserved.