получите вторую и четвертую субботу вместе со всеми воскресеньями предыдущего месяца в оракуле - PullRequest
1 голос
/ 15 марта 2019

У меня есть следующий запрос, который дает вторую и четвертую субботу предыдущего месяца вместе со всеми воскресеньями предыдущего месяца:

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)

Но я чувствую, что должен быть более простой способ получитьтот же результат в оракуле. Любая помощь в этом отношении приветствуется.Мое требование для формата даты: «ГГГГММДД».

Ответы [ 2 ]

0 голосов
/ 15 марта 2019

Отредактировано, потому что я неправильно понял вопрос:

Я думаю, вы хотите что-то вроде следующего:

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.
0 голосов
/ 15 марта 2019

Например, как здесь:

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, так как мой родительский запрос имеет тип from: 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() для подсчета, просто чтобы показать разные подходы, но вы можете использовать все, что вам понятнее (названия дней, sum или count вместо rank).

...