달바라기
오라클에서 쿼리로 달력 만들기 본문
1. connect by 절에 rownum 조건으로 해당 월의 마지막 일자 만큼 반복
2. rownum을 사용하여 해당월의 모든 일자 생성
SELECT TO_CHAR(MM + ROWNUM - 1, 'YYYYMMDD') DD
FROM (SELECT TO_DATE(TO_CHAR(SYSDATE, 'YYYYMM'), 'YYYYMM') MM FROM DUAL)
CONNECT BY ROWNUM <= TO_CHAR(LAST_DAY(MM), 'dd')
- 이후 달력형으로 만들기 위해 월일, 일, 요일구분, 년중 주차 값을 추가
SELECT TO_CHAR(MM + ROWNUM - 1, 'YYYYMMDD') ORDDD
, TO_CHAR(MM + ROWNUM - 1, 'MMDD') MMDD
, TO_CHAR(MM + ROWNUM - 1, 'dd') DAYNUM
, TO_CHAR(MM + ROWNUM - 1, 'd') WEEKDAY
-- 오라클 주의 시작은 월요일 부터. 일요일 부터 시작하기 위해 1을 더한다.
, TO_CHAR(MM + ROWNUM, 'IW') WEEKNUM
FROM (SELECT TO_DATE(TO_CHAR(SYSDATE, 'YYYYMM'), 'YYYYMM') MM FROM DUAL)
CONNECT BY ROWNUM <= TO_CHAR(LAST_DAY(MM), 'dd')
- 주차로 그룹하고 요일구분으로 각 일자 표시
SELECT MAX(DECODE(WEEKDAY, 1, DAYNUM)) SUN
, MAX(DECODE(WEEKDAY, 2, DAYNUM)) MON
, MAX(DECODE(WEEKDAY, 3, DAYNUM)) TUE
, MAX(DECODE(WEEKDAY, 4, DAYNUM)) WED
, MAX(DECODE(WEEKDAY, 5, DAYNUM)) THU
, MAX(DECODE(WEEKDAY, 6, DAYNUM)) FRI
, MAX(DECODE(WEEKDAY, 7, DAYNUM)) SAT
FROM (SELECT TO_CHAR(MM + ROWNUM - 1, 'YYYYMMDD') ORDDD
, TO_CHAR(MM + ROWNUM - 1, 'MMDD') MMDD
, TO_CHAR(MM + ROWNUM - 1, 'dd') DAYNUM
, TO_CHAR(MM + ROWNUM - 1, 'd') WEEKDAY
-- 오라클 주의 시작은 월요일 부터. 일요일 부터 시작하기 위해 1을 더한다.
, TO_CHAR(MM + ROWNUM, 'IW') WEEKNUM
FROM (SELECT TO_DATE(TO_CHAR(SYSDATE, 'YYYYMM'), 'YYYYMM') MM FROM DUAL)
CONNECT BY ROWNUM <= TO_CHAR(LAST_DAY(MM), 'dd')) A
GROUP BY WEEKNUM
-- 12월31일의 경우 주차를 계산할 때 1월1일을 보게되고 주차는 1이 되기 때문에
-- 해당 요일이 일요일이면 '99991231'로 처리
ORDER BY DECODE(MIN(MMDD), '1231', '99991231', MIN(A.ORDDD))
주의! 주차를 일요일부터 적용하는 것 처럼 보이기 위해 1일 더해 계산. 즉 12월 31일은 다음해 1월 1일의 값.
주의! 주차 계산 규칙에 의해 1월의 첫주가 이전해 마지막 주차 값을 가지기도 하며,
12월의 마지막 주가 다음해의 첫 주차 값을 가지기도 한다.
해서 그주의 가장 작은 일자가 12월 31일 경우는 가장 큰 일자 값으로 해서 정렬하였음.
ps. 글작성후 https://m.blog.naver.com/cofla_qkqh/221120597766 에서 조금 더 간단한 방법 발견
SELECT MIN (DECODE (TO_CHAR (YM + rownum - 1, 'D'), '1', TO_CHAR (YM + rownum - 1, 'YYYY-MM-DD'))) SUN
, MIN (DECODE (TO_CHAR (YM + rownum - 1, 'D'), '2', TO_CHAR (YM + rownum - 1, 'YYYY-MM-DD'))) MON
, MIN (DECODE (TO_CHAR (YM + rownum - 1, 'D'), '3', TO_CHAR (YM + rownum - 1, 'YYYY-MM-DD'))) TUE
, MIN (DECODE (TO_CHAR (YM + rownum - 1, 'D'), '4', TO_CHAR (YM + rownum - 1, 'YYYY-MM-DD'))) WED
, MIN (DECODE (TO_CHAR (YM + rownum - 1, 'D'), '5', TO_CHAR (YM + rownum - 1, 'YYYY-MM-DD'))) THU
, MIN (DECODE (TO_CHAR (YM + rownum - 1, 'D'), '6', TO_CHAR (YM + rownum - 1, 'YYYY-MM-DD'))) FRI
, MIN (DECODE (TO_CHAR (YM + rownum - 1, 'D'), '7', TO_CHAR (YM + rownum - 1, 'YYYY-MM-DD'))) SAT
FROM (select to_date('202412','yyyymm') ym FROM DUAL)
CONNECT BY rownum <= to_char(LAST_DAY (YM), 'DD')
GROUP BY TRUNC (YM + rownum, 'iw')
ORDER BY min(rownum) ;
TRUNC (YM + rownum, 'iw') 을 사용하면 해당 주차의 가장 작은 일자를 가져옴.
min(rownum)를 사용하면 1월 초, 12월 말 주차의 문제가 해결됨