【问题标题】:oracle pl-sql find the 3rd wednesday of a given dateoracle pl-sql 查找给定日期的第三个星期三
【发布时间】:2020-05-30 01:44:55
【问题描述】:

目前我有一个进程,它接受一个日期变量 EG:'01-MAR-2026',然后它会遍历这个日期,检查当天是否是星期三。如果是这样,则增加一个计数器,否则添加 1 天并再次检查。 当星期三计数 = 3 时退出。

IF (to_char(v_Date,'dy') = 'wed') THEN
        v_NumWed := v_NumWed + 1;
END IF;

WHILE (v_NumWed != 3) LOOP
    v_Date := v_Date + interval '1' day;
    IF (to_char(v_Date, 'dy') = 'wed') THEN
        v_NumWed := v_NumWed + 1;
    END IF;
END LOOP;

但是我觉得有一种更简单的方法可以通过查询或不使用循环 EG 的方式来实现这一点:使用输入日期和查询来查找第一个星期三然后 + 14 天?

任何建议都会很棒,在此先感谢:)

编辑:我有类似的东西似乎可以工作,还考虑第一天是否是星期三本身。

select next_day(trunc(v_date, 'MM') - 1, 'WED'), next_day(trunc(v_date, 'MM') - 1, 'WED') + 14 into v_first, v_third from dual;

已解决:感谢大家的帮助,现在在 cmets 中找到了一些可能的解决方案!

【问题讨论】:

  • 所以对于 2026-03-01,您期望结果为 2026-03-18,对吗?如果原始日期本身是星期三怎么办 - 2026-03-04 是否也应该映射到 2026-03-18 或 2026-03-25?
  • Alex - 很好的测试用例,我认为底部的编辑代码涵盖了它。 01-APR-20 是星期三,进入 v_first。 15 号是第三个星期三,进入 v_third。本质上不是优雅的外观,但它可以工作

标签: sql oracle date plsql


【解决方案1】:

这个怎么样?找到某个日期之后的第一个星期三(使用 NEXT_DAY),然后加上 14 天(即 2 周)以找到第三个星期三。

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

Session altered.

SQL> alter session set nls_date_language = 'english';

Session altered.

SQL> WITH test (col)
  2       AS (SELECT DATE '2020-01-27' FROM DUAL
  3           UNION ALL
  4           SELECT DATE '2020-02-06' FROM DUAL
  5           UNION ALL
  6           SELECT DATE '2020-02-12' FROM DUAL)
  7  SELECT col, NEXT_DAY (col, 'wed') + 14 next_3
  8    FROM test;

COL        NEXT_3
---------- ----------
27.01.2020 12.02.2020
06.02.2020 26.02.2020
12.02.2020 04.03.2020

SQL>

[编辑]

如果您发布的评论意味着 - 对于任何日期 - 您想要找到该月的第三个星期三,然后将日期截断为 month(返回该月的第一天)并找到第三个星期三,注意该月的第一天是否是(或不是)星期三。

SQL> WITH test (col)
  2       AS (SELECT DATE '2020-01-27' FROM DUAL
  3           UNION ALL
  4           SELECT DATE '2020-02-06' FROM DUAL
  5           UNION ALL
  6           SELECT DATE '2020-03-18' FROM DUAL)
  7  SELECT col,
  8           NEXT_DAY (TRUNC (col, 'mm'), 'wed')
  9         + CASE
 10              WHEN TO_CHAR (TRUNC (col, 'mm'), 'dy') = 'wed' THEN 7
 11              ELSE 14
 12           END
 13            next_3
 14    FROM test;

COL        NEXT_3
---------- ----------
27.01.2020 15.01.2020
06.02.2020 19.02.2020
18.03.2020 18.03.2020

SQL>

【讨论】:

  • 目标是从该月的 1 号开始的一个月的第三个星期三,不能溢出到下个月 EG:不是每个第三个星期三滚动 :)
  • 啊哈;因此,根据日期,您希望找到该月的第三个星期三。我编辑了答案并添加了更多代码。看看有没有帮助。
  • 是的,我很抱歉,新代码看起来不错,我也会玩一下,谢谢你的帮助!
【解决方案2】:

要从某个日期获取第三个星期三,如果 ti 本身是星期三,则包括该日期,您可以这样做:

select next_day(date '2026-03-01' + 13, 'Wednesday') from dual;

NEXT_DAY(D
----------
2026-03-18

next_day 函数有点尴尬,因为它对 NLS 敏感,并且没有覆盖(如 to_char() 那样) - 所以 NLS 会话语言和日期名称/缩写必须在相同的语言。如果您无法控制,那么您可以通过从已知的固定日期获取当前语言的日期名称来解决它:

alter session set nls_date_language = 'French';

select to_char(date '2026-03-01', 'Day'),
  next_day(date '2026-03-01' + 13, to_char(date '1999-12-29', 'Day'))
from dual;

TO_CHAR( NEXT_DAY(D
-------- ----------
Dimanche 2026-03-18

带有一些示例日期的演示:

with t (sample_date) as (
  select date '2026-02-15' + level
  from dual
  connect by level <= 31
)
select sample_date, next_day(sample_date + 13, 'Wednesday') as third_wed
from t
order by sample_date;

SAMPLE_DAT THIRD_WED 
---------- ----------
2026-02-16 2026-03-04
2026-02-17 2026-03-04
2026-02-18 2026-03-04
2026-02-19 2026-03-11
2026-02-20 2026-03-11
2026-02-21 2026-03-11
2026-02-22 2026-03-11
2026-02-23 2026-03-11
2026-02-24 2026-03-11
2026-02-25 2026-03-11
2026-02-26 2026-03-18
2026-02-27 2026-03-18
2026-02-28 2026-03-18
2026-03-01 2026-03-18
2026-03-02 2026-03-18
2026-03-03 2026-03-18
2026-03-04 2026-03-18
2026-03-05 2026-03-25
2026-03-06 2026-03-25
2026-03-07 2026-03-25
2026-03-08 2026-03-25
2026-03-09 2026-03-25
2026-03-10 2026-03-25
2026-03-11 2026-03-25
2026-03-12 2026-04-01
2026-03-13 2026-04-01
2026-03-14 2026-04-01
2026-03-15 2026-04-01
2026-03-16 2026-04-01
2026-03-17 2026-04-01
2026-03-18 2026-04-01

【讨论】:

  • 感谢亚历克斯,意识到我应该多解释一下数据集。开始日始终为 01,月份始终为 Mar、Jun、Sep、Dec,但年份可以是从当前开始的任何年份
  • @C-MATT - 这仍然有效,不是吗?您将不会遇到大多数日期。这确实不是您的问题所说的,但是您的方法也应该没问题;虽然trunc() 看起来有点无意义,但您仍然可以使用 +13 而不是 -1 + 14。基本思路相同。
  • 看到您的更新,忘记了 NLS_ 影响...原始代码检查星期几 = 4 仅适用于美国,因为他们的第 1 天是星期天,所以第 4 天是星期三。此代码可能会在全球范围内运行,因此 oracle nls_database 设置设置为 America 的地区、语言和日期语言。你觉得这样好吗
【解决方案3】:

我知道你已经解决了这个问题,只是想给你看另一个例子:

DECLARE
        dStartDate DATE := SYSDATE;
        dNextWednesDay DATE;
BEGIN
        FOR n IN 1..3 LOOP
                dNextWednesDay := NEXT_DAY(dStartDate, 'WEDNESDAY');
                DBMS_OUTPUT.PUT_LINE(dNextWednesDay);

                dStartDate := dNextWednesDay +1;
        END LOOP; 
END;
/

输出:

2020-02-19 15:33:58
2020-02-26 15:33:58
2020-03-04 15:33:58

【讨论】:

    猜你喜欢
    • 2013-05-15
    • 1970-01-01
    • 2011-10-24
    • 2012-11-22
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 2016-11-30
    相关资源
    最近更新 更多