在甲骨文中获取第二个和第四个星期六以及上个月的所有星期日

时间:2019-03-15 16:18:51

标签: sql oracle date-arithmetic

我有以下查询,该查询给出了上个月的第二个和第四个星期六以及上个月的所有星期日:

SELECT to_char(NEXT_DAY(NEXT_DAY(NEXT_DAY(NEXT_DAY(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1, 'SATURDAY'), 'SATURDAY'),'SATURDAY'),'SATURDAY'),'YYYYMMDD') SECOND_SATURDAY 
FROM DUAL
UNION ALL
SELECT to_char(NEXT_DAY(NEXT_DAY(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1, 'SATURDAY'),'SATURDAY'),'YYYYMMDD') SECOND_SATURDAY 
FROM DUAL
UNION ALL
select distinct day_date from
(SELECT to_char(NEXT_DAY(LEVEL + TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1,'SUNDAY'),'YYYYMMDD') day_date
FROM DUAL
CONNECT BY LEVEL <=  ADD_MONTHS(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH'), 1) - TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH'))
where substr(day_date,1,6) in (select to_char((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL),'YYYYMM') from dual)

但是我觉得在oracle中必须有一种更简单的方法来获得相同的结果。欢迎在这方面的任何帮助。我对日期格式的要求是“ YYYYMMDD”。

2 个答案:

答案 0 :(得分:0)

例如此处的

with 
  t1 as (select add_months(trunc(sysdate, 'month'), -1) dt from dual),
  t2 as (
    select dt + level - 1 dt, to_char(dt + level - 1, 'dy', 'nls_date_language=english') dy
      from t1 connect by dt + level - 1 < trunc(sysdate, 'month'))
select to_char(dt, 'yyyymmdd') dt, dy
  from (
    select dt, dy, sum(case when dy = 'sat' then 1 end) over (order by dt) sm from t2)
  where dy = 'sun' or (dy = 'sat' and sm in (2, 4))

结果:

DT       DY
-------- ---
20190203 sun
20190209 sat
20190210 sun
20190217 sun
20190223 sat
20190224 sun

我生成了上个月的所有日期,分配了英文日期名称,有条件地计算了星期六,并且只显示了有趣的日期。


编辑:

  

这可行,但是自从我开始以来,有什么方法可以绕过with子句   父查询的来源为:x为(....其中,日期为(“   天”)和...)。因此它呈现出嵌套的情况。

是的,您可以轻松地将其转换,例如此处:

select to_char(dt, 'yyyymmdd') dt
  from (
    select dt, dn, rank() over (order by mod(dn, 6), dt) rnk
      from (
        select d + level - 1 dt, d + level - trunc(d + level - 1, 'iw') dn
          from (select add_months(trunc(sysdate, 'month'), -1) d from dual)
          connect by level <= add_months(d, 1) - d))
  where dn = 7 or (dn = 6 and rnk in (2, 4)) 

dbfiddle demo

with子句使步骤更易读。现在,我还使用天数和mod()进行计数,只是为了显示不同的方法,但是您可以使用更清晰的名称(天名sumcount而不是{{1 }}。

答案 1 :(得分:0)

编辑是因为我误解了这个问题:

我认为您想要以下内容:

SELECT TO_CHAR(my_date, 'YYYYMMDD') AS my_formatted_date
  FROM (
    SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2))+7, 'SATURDAY') AS my_date
      FROM dual
     UNION ALL
    SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2))+21, 'SATURDAY')
      FROM dual
     UNION ALL
    SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY') + (LEVEL-1)*7
      FROM dual
   CONNECT BY NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY') + (LEVEL-1)*7 < TRUNC(SYSDATE, 'MONTH')
);

在查询的第一部分中,我确定上个月的最后一天,然后获取在该日期后至少一个星期之后的第一个星期六(该月的第二个星期六将是从8日到14)。然后我得到的第一个星期六至少在上个月的最后一天之后的三周内落下(第四个星期六从22日到28日不等)。最后,我从上一个月的最后一天(即两个月前)的第一个星期日开始,遍历上个月的星期日。您也可以使用NEXT_DAY(TRUNC(ADD_MONTHS(SYSDATE, -1) - 1), 'SUNDAY')代替NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY')

MY_FORMA
--------
20190209
20190223
20190203
20190210
20190217
20190224

6 rows selected.