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

kpbwa7wx  于 2023-03-22  发布在  Oracle
关注(0)|答案(3)|浏览(222)

我想在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  |           |
6mzjoqzu

6mzjoqzu1#

您的转换可以简化为:

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

IW元素是ISO日历周,它总是从星期一开始,截断它会为该周的每一天提供相同的周开始日期;加上六个调整,基本上从周二开始
因此,首先将字符串转换为日期,将变为:

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

(Not你应该把日期存储为字符串它们在你的样本数据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_DAY|新_DT|
| - ------|- ------|- ------|
| 二十三年一月二十九日|星期日|2023年1月30日|
| 23年1月30日|星期一|23年1月30日|
| 2023年1月31日|星期二|2023年2月6日|
| 2023年2月1日|星期三|2023年2月6日|
| 2023年2月2日|星期四|2023年2月6日|
| 2023年2月3日|星期五|2023年2月6日|
| 2023年2月4日|星期六|2023年2月6日|
| 2023年2月5日|星期日|2023年2月6日|
| 2023年2月6日|星期一|2023年2月6日|
| 2023年2月7日|星期二|2023年2月13日|
| 2023年2月8日|星期三|2023年2月13日|
| 2023年2月9日|星期四|2023年2月13日|
fiddle
我在to_date()中加入了可选的第三个参数,这样即使会话日期语言是其他语言,月份缩写也能被识别出来。如果你从真实的日期而不是字符串开始,你也不必担心。

wfypjpf4

wfypjpf42#

您可以将生成器简化为:

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_DAY|新_DT|
| - ------|- ------|- ------|
| 2023年1月29日00时00分|星期日|2023年1月30日00时00分|
| 2023年1月30日00时00分|星期一|2023年1月30日00时00分|
| 2023年1月31日上午00时00分|星期二|2023年2月6日00时00分|
| 2023年2月1日00时00分|星期三|2023年2月6日00时00分|
| 2023年2月2日00时00分|星期四|2023年2月6日00时00分|
| 2023年2月3日00时00分|星期五|2023年2月6日00时00分|
| 2023年2月4日00时00分|星期六|2023年2月6日00时00分|
| 2023年2月5日00时00分|星期日|2023年2月6日00时00分|
| 2023年2月6日00时00分|星期一|2023年2月6日00时00分|
| 2023年2月7日00时00分|星期二|2023年2月13日00时00分|
| 2023年2月8日00时00分|星期三|2023年2月13日00时00分|
| 2023年2月9日00时00分|星期四|2023年2月13日00时00分|
fiddle
我到底做错了什么?
TO_DATE(date_value, 'DAY')输出一个固定长度的字符串,它是您的语言中最长的日期名称的长度。对于英语,它是'WEDNESDAY',其他字符串将用空格填充,如'MONDAY '
如果你不想填充字符串,那么使用TO_DATE(date_value, 'fmDAY'),然后你的代码就可以工作了(如果你正确地拼写了TUESDAY并且隐式日期转换成功的话)。
fiddle

kmbjn2e3

kmbjn2e33#

有几件事:对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')
;

相关问题