월 주차 구하는 방식에 대해서 질문 드립니다. 9

by 환영 [PL/SQL] [2024.08.23 11:04:43]


안녕하세요.

항상 사이트 눈팅만 하다가 업무적으로 해결이 어려운 문제가 있어 질문하게 되었습니다.

 

시작일자(예 : 20240101) ~ 종료일자(예 : 20251231) 사이의 주차를 구해야하는데,

 

1월의 5주차의 범위는 01.28 ~ 02.03이 되고

2월의 1주차도 01.28 ~ 02.03이 되게끔 처리하려면 어떻게 하는게 좋을까요?

 

현재 개발하고 있는 프로그램 내에선 요일을 입력받아 해당 요일을 기준으로 주차를 계산하고 있어서 5주차에 대한 개념이 명확하지 않아 제대로 시스템에 입력되지 않는 현상이 생겼습니다.

 

시작일자 ~ 종료일자 사이에 특정 요일을 기준으로 주차에 대한 개념을 정의해야 하는데 떠오르는 방법이 없어서 질문드립니다. (_ _)

by 우주민 [2024.08.23 11:12:31]

1월 5주차와 2월 1주차 값이 동일하게 만드시는 이유가 궁금하네요.

특정일에 2개의 주차 개념이 들어가는것이 생소합니다.


by 환영 [2024.08.23 11:27:32]

저도 사실 해당 부분에 대해서 의아함을 가지고 작업을 시작한 상태라 자세한 이유는 잘 모르겠습니다.

프로시저 상으로 1주차~5주차에 해당하는 전략을 시스템상에서 등록을 하게 되는데, 이전 프로시저 구성에선 요일을 기준으로 프로시저를 등록하고 있습니다.

예를 들어, 20240401 ~ 20251231 범위 내의 날짜로 해당 전략을 등록할 경우 1~5주차 X요일에 대해 선택을 하게 되는데,

만약 5주차의 전략을 매주 화요일에 생성한다고 했을때 해당 범위는 04.30 ~ 05.06로 잡히게 됩니다.

이렇게 됐을 때, 다음 주차를 판별하면 05.07이 5월의 1주차가  돼버리고, 이후 전략이 등록될땐 5월에는 5주차가 생성이 되지 않는 것이지요.

 

그래서 2개의 주차를 중복되게 넣을 수 있는 방법이 있을까해서 질문드렸습니다. 뭔가 더 좋은 방법이 있으면 좋을거같은데 "요일을 선택한다." 라는 개념때문에 딱히 떠오르는 방법이 없는 상황입니다 ㅠㅠ


by 환영 [2024.08.23 14:12:20]

네 맞습니다! 무조건 해당 월의 1일이 포함돼 있으면 1주차로 봐야합니다.


by 우주민 [2024.08.23 13:17:22]

화요일을 기준으로 주차를 계산하는 것이라면 20240507 은 5월 1주차가 맞는거 같은데요.

혹시 추가적으로 해당월의 1일이 포함된 주차는 무조건 해당월의 1주차가 되어야 하는 정의가 있을까요?


by 환영 [2024.08.23 11:34:49]

매월 주차를 새로 구한다라는 개념으로 접근하고 있는 상태입니다!


by 마농 [2024.08.23 12:14:07]

원하시는 결과가 어떻게 되는지 표형태로 그려주세요.
입력 대비 결과표


by 환영 [2024.08.23 13:02:24]
YY MM FIRST_DD LAST_DD RN DAY STR_DD END_DD DAY_CD WEEK_OF_MONTH
2024 04 2024-04-01 2024-04-30 1 월요일 2024-04-01 2024-04-07   1
2024 04 2024-04-01 2024-04-30 2 화요일 2024-04-02 2024-04-08   1
2024 04 2024-04-01 2024-04-30 3 수요일 2024-04-03 2024-04-09   1
2024 04 2024-04-01 2024-04-30 4 목요일 2024-04-04 2024-04-10   1
2024 04 2024-04-01 2024-04-30 5 금요일 2024-04-05 2024-04-11   1
2024 04 2024-04-01 2024-04-30 6 토요일 2024-04-06 2024-04-12   1
2024 04 2024-04-01 2024-04-30 7 일요일 2024-04-07 2024-04-13   2
2024 04 2024-04-01 2024-04-30 8 월요일 2024-04-08 2024-04-14   2
          (중략)        
2024 04 2024-04-01 2024-04-30   일요일 2024-04-28 2024-05-04   5
          월요일 2024-04-29 2024-05-05   5
          화요일 2024-04-30 2024-05-06   5
          수요일 2024-05-01 2024-05-07   1
          (중략)        
                   
                   
                   
                   
                   

이런 형태로 진행을 하고, 내가 선택한 요일이 (수요일) 일때

YY MM FIRST_DD LAST_DD RN DAY STR_DD END_DD DAY_CD WEEK_OF_MONTH
                   

만약 2024-05-01 ~ 2024-05-07 기간 안에 해당하는 수요일 기준으로 전략을 생성하게 되면 다음 수요일인 5월 8일이 5월의 1주차가 되어 버립니다.

실제로 5월 8일은 2주차로 봐야하는 상황입니다!

어떤 방식으로 처리하면 좋을지 의견 여쭙습니다 (_ _)..


by 환영 [2024.08.23 14:38:22]

혹시 참고가 되실까하여, 현재 사용하고 있는 SQL 구문도 따로 남겨두겠습니다.

 

SELECT TO_CHAR(YMD, 'YYYY') AS YY,

TO_CHAR(YMD, 'MM') AS MM,

TO_DATE(TO_CHAR(YMD, 'YYYYMM'), 'YYYYMM') AS FIRST_DD,

LAST_DAY(YMD) AS LAST_DD,

ROWNUM AS RN,

TO_CHAR(YMD, 'DAY') AS DAY,

YMD AS STR_DD,

YMD+6 AS END_DD,

'000' || TO_CHAR(YMD, 'D') AS DAY_CD,

TO_CHAR(YMD, 'W') AS WEEK_OF_MONTH

FROM ( SELECT TO_DATE(REPLACE('20240401', '-', ''), 'YYYYMMDD') + (LEVEL-1) AS YMD

                FROM DUAL

                CONNECT BY LEVEL <= TO_DATE(REPLACE('20241231', '-', ''), 'YYYYMMDD') - TO_DATE(REPLACE('20240401', '-', ''), 'YYYYMMDD')

)

 


by 우주민 [2024.08.23 15:47:10]
SELECT YMD as S_DATE
      ,YMD + 6 AS E_DATE
      ,TO_CHAR(YMD, 'DAY') AS DAY
      ,TO_CHAR(YMD, 'D') AS D
      ,TO_CHAR(YMD, 'W') AS WEEK_OF_MONTH
  FROM (SELECT TO_DATE(REPLACE('20240301', '-', ''), 'YYYYMMDD') + (LEVEL-1) AS YMD
          FROM DUAL
       CONNECT BY LEVEL <= TO_DATE(REPLACE('20241231', '-', ''), 'YYYYMMDD') 
                         - TO_DATE(REPLACE('20240301', '-', ''), 'YYYYMMDD')
)
WHERE TO_CHAR(YMD, 'D') = 4

글쎄요. 정상적으로 잘 나오는 데이터 아닌가 싶은데....

TO_CHAR(YMD, 'D') = 4 에서 4는 수요일 값을 넣은 조건식 입니다.

예시로 보신 5월 8일 은 2주차로 나오게 됩니다.

무언가 질문의 요지를 제가 이해 못한거 같기도 하고....


by 마농 [2024.08.26 08:50:26]

원하는 결과를 입력 대비 결과표 형태로 그려달라고 했는데
그려 주신 표가 좀 모호합니다.
최종 원하는 결과표가 맞는지?


by 마농 [2024.08.26 10:27:28]

마지막 5주차가 다음월 1주차로 중복되어야 한다면?
처음 1주차 또한 이전월 마지막 주차와 중복되어야 합니다.
이런 개념이면 현재 1주차로 설정된 부분이 달라져야 합니다. 앞으로 당겨져야 합니다.
이렇게 되면 6주차까지 가능합니다.
4월 화요일 기준으로 뽑게 된다면? 결과는 다음과 같게 되겠지요.
2024.03.26 ~ 2024.04.01 1주차
2024.04.02 ~ 2024.04.08 2주차
2024.04.09 ~ 2024.04.15 3주차
2024.04.16 ~ 2024.04.22 4주차
2024.04.23 ~ 2024.04.29 5주차
2024.04.30 ~ 2024.05.06 6주차
즉, 월에 따라 4주차~6주차까지 가변적으로 나올 듯 합니다.

만약 화요일 시작 기준으로 월이 겹치는 주차의 경우
더 많은 월이 포함된 월로 산입시키는 방안이 있습니다.
2024.04.30 ~ 2024.05.06 을 보면
4월은 1일(30), 5월은 6일(1,2,3,4,5,6) 이므로 5월 1주차로 산입
2024.03.26 ~ 2024.04.01 을 보면
4월은 1일(30), 3월은 6일(26~31) 이므로 3월 마지막 주차로 산입
2024.03.26 ~ 2024.04.01 전월 마지막 주차
2024.04.02 ~ 2024.04.08 1주차
2024.04.09 ~ 2024.04.15 2주차
2024.04.16 ~ 2024.04.22 3주차
2024.04.23 ~ 2024.04.29 4주차
2024.04.30 ~ 2024.05.06 다음월 1주차
이렇게 되면 중복 출력되는 주는 없습니다.


by 환영 [2024.08.26 11:14:38]
YY MM DD FIRST_DD LAST_DD DAY STR_DD END_DD DAY_CD WEEK_OF_MONTH
2024 04 28 2024-04-01 2024-04-30 일요일 2024-04-28 2024-05-04 0001 5
2024 04 29 2024-04-01 2024-04-30 월요일 2024-04-29 2024-05-05 0002 5
2024 04 30 2024-04-01 2024-04-30 화요일 2024-04-30 2024-05-06 0003 5
2024 05 01 2024-05-01 2024-05-31 수요일 2024-05-01 2024-05-07 0004 1
2024 05 02 2024-05-01 2024-05-31 목요일 2024-05-02 2024-05-08 0005 1
2024 05 03 2024-05-01 2024-05-31 금요일 2024-05-03 2024-05-09 0006 1
2024 05 04 2024-05-01 2024-05-31 토요일 2024-05-04 2024-05-10 0007 1
2024 05 05 2024-05-01 2024-05-31 일요일 2024-05-05 2024-05-11 0001 2
2024 05 06 2024-05-01 2024-05-31 월요일 2024-05-06 2024-05-12 0002 2

시작일을 기준으로 5월 1일부터 4일은 5월의 1주차가 되어야하고

마찬가지로 5월5일부터 5월 11일은 2주차가 되어야합니다.

달력을 기준으로 봤을때 눈에 보이는 한줄이 주차에 해당하며

다음줄로 넘어가게되면 무조건 다음주차로 넘어가야 하는 개념입니다!

 

현재는 4월 5주차의 화요일을 선택하게 되면

2024-04-30 ~ 2024-05-06 (5주차)

2024-05-07 ~ 2024-05-13 (1주차)

2024-05-14 ~ 2024-05-20 (2주차)

.

.

식으로 작업이 생성되는데

저는

2024-05-07 ~ 2024-05-13 해당 작업을 살펴보면

시작일이 되는 05-07 일은 5월의 2주차에 해당하므로

2024-04-30 ~ 2024-05-06 (5주차)

2024-05-07 ~ 2024-05-13 (2주차)

2024-05-14 ~ 2024-05-20 (3주차)

 

이런 형태로 데이터를 뽑을 수 있는 방법을 찾고 있습니다.

종료일자와 관계없이 시작일자를 기준으로 해당일자가 속한 주차가 몇주차인지 구해서 해당 주차를 출력하면 될 것 같은데

현재는 그 방법으로 토요일 기준으로 주차정보를 한번 구하여(T2) 원본 테이블(T1)과 비교하는 방식으로 주차 정보를 변경할 수 있게 시도중입니다.

추가) 시작일 기준으로 토요일이 다음 월로 넘어가게 된다면 해당 주의 주차는 5가 되도록 처리합니다!


by 마농 [2024.08.26 12:45:11]

4월 화요일 시작 기준으로 보면
2024-04-28 ~ 2024-05-04 은
4월의 마지막 주차이기도 하고 5월의 1주차이기도 합니다.
이 때 마지막 주차만 표현하고 1주차는 생략하면 되겠네요?
그런데. 해당 주차는 4월 5주차라고 하셨지만 4월 6주차입니다.

화요일 시작 기준
3월 5주차 2024-03-26 ~ 2024-04-01
4월 2주차 2024-04-02 ~ 2024-04-08
4월 3주차 2024-04-09 ~ 2024-04-15
4월 4주차 2024-04-16 ~ 2024-04-22
4월 5주차 2024-04-23 ~ 2024-04-29
4월 6주차 2024-04-30 ~ 2024-05-06
5월 2주차 2024-05-07 ~ 2024-05-13
 


by 마농 [2024.08.26 12:58:46]

다시 보니 제시하신 주차에서
2024-04-30 ~ 2024-05-06 (5주차) <-- 이부분만 1주차로 바꾸면 될 것 같습니다.
2024-05-07 ~ 2024-05-13 (2주차)
2024-05-14 ~ 2024-05-20 (3주차)
그러면 되지 않나요? 제가 제시했던 두가지 방안중에 두번째 방안
전월 5주차 다음 2주차 나오는 것보다 이게 더 명확합니다.
일주일중 더많은 월을 포함함 월의 주차로 산입시키기


by 환영 [2024.08.26 13:19:47]

3월 5주차 2024-03-25 ~ 2024-04-02

4월 1주차 2024-03-25 ~ 2024-04-02

해당 범위 내에 5주차와 1주차가 겹치게 나오도록 하는 것이 첫번째 목표이긴 했습니다.

말씀해주신 방법 중 5주차에 해당하는 데이터를 1주차로 변경하면 되지 않느냐? 라는 부분에 대해서는 저도 그렇게 생각을 했었다가, 그럼 5주차에 해당하는 데이터가 사라지니 5주차에 대한 작업이 누락이 돼서 등록이 되지 않더라구요.

 

현재 프로그램 상에선

시작기간 ~ 종료기간을 입력받고

1주차 ~ 5주차 중 한가지 주차를 선택하여

월요일~일요일에 해당하는 날짜를 골라 작업을 생성하게 됩니다.

 

예 : 2024-04-01(시작기간) ~ 2024-12-31(종료기간)

5주차 선택, 화요일 선택

 

데이터 : 2024-04-30 ~ 2024-05-06 (5주차, 화요일)

2024-05-07 ~ 2024-05-13 (1주차)

2024-05-14 ~ 2024-05-20 (2주차)

2024-05-21 ~ 2024-05-27 (3주차)

2024-05-28 ~ 2024-06-04 (4주차)

2024-06-05 ~ 2024-06-11 (1주차)

2024-06-12 ~ 2024-06-18 (2주차)

.

.

이런 식으로 진행했을 때 5주차가 계속 누락되어 5주차 작업이 생성되지 않고 있습니다.

종료기간과 관계없이 주차의 시작일자가 1~5주차 중 몇주차에 해당하는지에 대해 알고, 강제로 세팅하는 방법이 있는지 궁금합니다.

저도 질문을 계속 하면서 산으로 가는 느낌이긴한데 너무나 죄송합니다 ㅠㅠ


by 환영 [2024.08.26 13:32:34]

SELECT A.YY, A.MM, A.DD, A.FIRST_DD, A.LAST_DD, A.RN, A.DAY, A.STR_DD, A.END_DD, A.DAY_CD,

CASE WHEN A.STR_DD >= B.STR_DD AND A.STR_DD <= B.END_DD THEN B.WEEK_OF_MONTH

ELSE A.WEEK_OF_MONTH

END AS WEEK_OF_MONTH

FROM (

SELECT TO_CHAR(YMD, 'YYYY') AS YY,

TO_CHAR(YMD, 'MM') AS MM,

TO_DATE(TO_CHAR(YMD, 'YYYYMM'), 'YYYYMM') AS FIRST_DD,

LAST_DAY(YMD) AS LAST_DD,

ROWNUM AS RN,

TO_CHAR(YMD, 'DAY') AS DAY,

YMD AS STR_DD,

YMD+6 AS END_DD,

'000' || TO_CHAR(YMD, 'D') AS DAY_CD,

TO_CHAR(YMD, 'W') AS WEEK_OF_MONTH

FROM ( SELECT TO_DATE(REPLACE('20240401', '-', ''), 'YYYYMMDD') + (LEVEL-1) AS YMD

                FROM DUAL

                CONNECT BY LEVEL <= TO_DATE(REPLACE('20241231', '-', ''), 'YYYYMMDD') - TO_DATE(REPLACE('20240401', '-', ''), 'YYYYMMDD')

)

) A,

(

SELECT TO_CHAR(YMD, 'YYYY') AS YY,

TO_CHAR(YMD, 'MM') AS MM,

TO_DATE(TO_CHAR(YMD, 'YYYYMM'), 'YYYYMM') AS FIRST_DD,

LAST_DAY(YMD) AS LAST_DD,

ROWNUM AS RN,

TO_CHAR(YMD, 'DAY') AS DAY,

YMD-6 AS STR_DD,

YMD AS END_DD,

'000' || TO_CHAR(YMD, 'D') AS DAY_CD,

TO_CHAR(YMD, 'W') AS WEEK_OF_MONTH

FROM ( SELECT TO_DATE(REPLACE('20240401', '-', ''), 'YYYYMMDD') + (LEVEL-1) AS YMD

                FROM DUAL

                CONNECT BY LEVEL <= TO_DATE(REPLACE('20241231', '-', ''), 'YYYYMMDD') - TO_DATE(REPLACE('20240401', '-', ''), 'YYYYMMDD')

)

WHERE '000' || TO_CHAR(YMD, 'D') = '0007'

) B

WHERE A.YY = B.YY(+)

AND A.STR_DD = B.STR_DD(+)

AND A.MM = B.MM(+)

ORDER BY STR_DD, WEEK_OF_MONTH

 

토요일을 기준으로 주차정보를 새롭게 정의해봤던 쿼리입니다.

A와 B를 비교해 A의 STR_DD가 B의 STR_DD ~ END_DD 범위 내에 있으면

B의 WEEK_OF_MONTH를, 없으면 A의 WEEK_OF_MONTH를 사용하도록 구현중이긴한데 중간중간 데이터가 잘못 나오고 있어서 다시 제자리걸음 중인 것 같네요..

해당 쿼리를 실행하면 STR_DD가 2024-05-05부터 2주차가 되는 것까진 정상적으로 출력되지만,

월요일과 화요일에 해당하는 2024-05-06, 2024-05-07의 데이터는 이상하게 1주차가 돼버리고

다음 2024-05-08 ~ 2024-05-11까진 또 정상적으로 2주차로 출력됩니다.


by 마농 [2024.08.26 13:41:44]

주차는 제가 제시한 둘중 하나를 선택하시는게 맞다고 생각이 됩니다.
다만 중복이 없어야 한다고 생각을 하고,
월이 겹치는 주의 처리 기준만 명확하게 잡으시면 됩니다.
- 주의 시작일이 포함된 월에 배치할 것인지? (4,5,6주차 발생 가능)
- 주중 더 많은 월이 포함된 월에 배치할 것인지? 

그리고 5주차가 누락되는 것은 당연한 것입니다.
당연한 걸 부정하려고 하니 안되는 것입니다.
만약 억지로 5주차를 만들고 2주차가 된다면?
반대로 1주차 뽑으면 1주차가 누락되겠지요?
예외조항을 넣으려고 하지 말고.
주차를 나눌 기준을 설정한 뒤 기준만 따르면 됩니다.

다시 한번 더
월이 겹치는 주의 처리 기준을 명확하게 잡으셔야 합니다.
- 주의 시작일이 포함된 월에 배치할 것인지? (4,5,6주차 발생 가능)
- 주중 더 많은 월이 포함된 월에 배치할 것인지? (4,5주차 발생 가능)


by 마농 [2024.08.26 14:46:00]

매월마다 5주차가 존재한다면? (12개월 * 5주차 = 60주) 입니다.
하지만 1년은 52 ~ 53 주만 있습니다.
5주차가 매월마다 있을 리가 없습니다.
없는 것을 억지로 조회하려고 하니 이상해 지는 것입니다.

주를 나누는 기준을 명확하게 정하시는 게 우선입니다.
다시 한번 더
월이 겹치는 주의 처리 기준을 명확하게 잡으셔야 합니다.
- 주의 시작일이 포함된 월에 배치할 것인지? (4,5,6주차 발생 가능)
- 주중 더 많은 월이 포함된 월에 배치할 것인지? (4,5주차 발생 가능)

기준이 정해지면
- 엑셀에 2024년도 월별 주차를 기준에 맞게 쭈욱 정리해 보세요.
- 위 질문처럼 요일마다 다 적으면 헷갈립니다.
- 특정요일 기준만 1년치를 정리해서 보세요.
- 요일마다 다른 시트로 정리하셔도 됩니다.
- 정리된 엑셀 결과를 가지고 해결방안을 모색하세요.
- 없는 5주차를 억지로 나오게 하는 것은 해결책이 아닙니다.


by 환영 [2024.08.26 16:17:14]

네 답변 감사합니다.

사실 처음부터 기준을 잡고 방법을 찾았으면 크게 문제가 되지 않았을텐데 요청사항 자체가 기준이 없기도 했고, 재확인 결과 없는 5주차를 억지로라도 나오게 해야하는 상황이 돼 버린 것 같습니다 ㅠㅠ

일단 얘기해주신대로 한번 더 정리해보고 추가 질문사항이 생기게 되면 재질문 드리겠습니다.

 

도움주신 모든 분들에게 감사드리며 항상 좋은 기운 얻고 갑니다^^!


by 우주민 [2024.08.27 10:27:46]

WITH WEEK_INFO AS (
    SELECT '20240101' AS S_DATE, '20241231' AS E_DATE
      FROM DUAL
)
,WEEK_R AS (
SELECT YMD AS YMD
      ,TO_CHAR(YMD, 'IW') AS WEEK
      ,TO_CHAR(YMD_MONTH_S, 'IW') AS WEEK_MONTH_S
      ,TO_CHAR(TRUNC(YMD ,'IW') ,'YYYY/MM/DD') AS S_DATE
      ,TO_CHAR(TRUNC(YMD ,'IW')  + 6,'YYYY/MM/DD') AS E_DATE
  FROM (SELECT TO_DATE(REPLACE(S_DATE, '-', ''), 'YYYYMMDD') + (LEVEL-1) AS YMD
             , TO_DATE(TO_CHAR(TO_DATE(REPLACE(S_DATE, '-', ''), 'YYYYMMDD') + (LEVEL-1), 'YYYYMM')||'01', 'YYYYMMDD') AS YMD_MONTH_S
          FROM WEEK_INFO
       CONNECT BY LEVEL <= TO_DATE(REPLACE(E_DATE, '-', ''), 'YYYYMMDD') 
                         - TO_DATE(REPLACE(S_DATE, '-', ''), 'YYYYMMDD')
       )
)
SELECT DISTINCT 
       TO_CHAR(YMD,'YYYY') AS YEAR
     , TO_CHAR(YMD,'MM') AS MONTH
     , CASE WHEN TO_CHAR(YMD,'MM') = '01' AND WEEK_MONTH_S > '50'
            THEN TO_CHAR(CASE WHEN WEEK > '50' THEN '00' ELSE WEEK END + 1,'00')
            WHEN TO_CHAR(YMD,'MM') = '12' AND WEEK < '10'
            THEN TO_CHAR((SELECT MAX(WEEK) + 1 FROM WEEK_R WHERE TO_CHAR(YMD, 'MM') = '12')- WEEK_MONTH_S + 1, '00')
            ELSE TO_CHAR(WEEK - WEEK_MONTH_S + 1,'00')
        END AS WEEK
     , S_DATE
     , E_DATE
FROM WEEK_R
ORDER BY 1, 2, 3

 

억지로나마 만든 쿼리 입니다.

1. 년초 / 말에 주차 계산 때문에 잡다한 식들이 들어갔습니다.(1월 1일이 전년도 마지막 주차 / 12월 31일 내년도 첫 주차 인 경우)

2. 월요일 부터 주차 계산이 들어가서 문의한 내용과 조금 상이 합니다.

3. 업무시간 중간에 간간히 하다보니 세세한 내용이 틀릴 수 있음을 이해해 주시고 참조용으로 봐주시면 좋겠습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입