DB의 내용은 대략 이렇습니다
컬럼 모두 VARCHAR2 문자열입니다
CREATE_YM | EMPLOYEE_CD | CD |
201611 | 112033 | 02 |
201610 | 112033 | 02 |
201609 | 112033 | 02 |
201608 | 112033 | 02 |
201608 | 443332 | 01 |
201607 | 112033 | 01 |
201606 | 112033 | 02 |
201607 | 443332 | 01 |
결과 내용
3개월 이하 | 331건 |
3~6개월 | 12건 |
7~11개월 | 3건 |
12개월 초과 | 2건 |
해당 데이터에서 보시면 사원번호 112033가 8월 부터 11월까지 02의 데이터가 연속 됩니다
그럼 조회되는 월분 11월을 기준으로 3개월 이상 02데이터 였기 때문에 3~6개월에 포함 시켜
건수가 카운트되는 식입니다
즉, 만약 02라는 데이터가 조회하려는 월분을 기준으로 같은 사원번호로 7개월간 있었다고 하면
7~11개월로 포함이 되어 해당 컬럼에 카운트가 되는 형식이며 중간에 02 이외의 다른 데이터가
해당 사원의 월분에 있으면 거기서 끝이며 월분은 거기까지 세어지게 됩니다
02라는 코드가 같은 사원번호로 매칭해서 몇 개월간 지속 되었느냐가 주인거 같은데
이전 데이터를 계속 거슬러 올라가서 02인지 확인해서 몇개월 지속 됬는지 가져온다는게 힘드네요..
이렇게 해서 전체데이터를 뽑아내야 하는데 접근법이 힘드네요 ..
힌트 부탁드려도 될까요?
WITH T AS ( SELECT '201611' AS CREATE_YM,'112033' AS EMPLOYEE_CD,'02' AS CD FROM DUAL UNION ALL SELECT '201610','112033','02' FROM DUAL UNION ALL SELECT '201609','112033','02' FROM DUAL UNION ALL SELECT '201608','112033','02' FROM DUAL UNION ALL SELECT '201608','443332','01' FROM DUAL UNION ALL SELECT '201607','112033','01' FROM DUAL UNION ALL SELECT '201605','112033','02' FROM DUAL UNION ALL SELECT '201607','443332','01' FROM DUAL ) SELECT CASE WHEN CNT < 3 THEN '3개월이하' WHEN CNT >=3 AND CNT <= 6 THEN '3~6개월' WHEN CNT >=7 AND CNT <= 11 THEN '7~11개월' WHEN CNT >=11 THEN '12개월초과' END GB, COUNT(1) CNT FROM ( SELECT EMPLOYEE_CD, COUNT(1) CNT FROM ( SELECT CREATE_YM, EMPLOYEE_CD, CD, BEFMONCD , SUM(DECODE(CD, BEFMONCD, 0, 1)) OVER(PARTITION BY EMPLOYEE_CD ORDER BY CREATE_YM) FG FROM ( SELECT CREATE_YM, EMPLOYEE_CD, CD , MAX(CD) OVER(PARTITION BY EMPLOYEE_CD ORDER BY TO_DATE(CREATE_YM||'01','yyyymmdd') RANGE BETWEEN INTERVAL '1' MONTH PRECEDING AND INTERVAL '1' MONTH PRECEDING) BEFMONCD FROM T WHERE CD = '02'--cd가 02인 것만 ) ORDER BY 2,1,3 ) GROUP BY EMPLOYEE_CD, FG ) GROUP BY CASE WHEN CNT < 3 THEN '3개월이하' WHEN CNT >=3 AND CNT <= 6 THEN '3~6개월' WHEN CNT >=7 AND CNT <= 11 THEN '7~11개월' WHEN CNT >=11 THEN '12개월초과' END
WITH t AS ( SELECT '201611' create_ym, '112033' employee_cd, '02' cd FROM dual UNION ALL SELECT '201610', '112033', '02' FROM dual UNION ALL SELECT '201609', '112033', '02' FROM dual UNION ALL SELECT '201608', '112033', '02' FROM dual UNION ALL SELECT '201608', '443332', '01' FROM dual UNION ALL SELECT '201607', '112033', '01' FROM dual UNION ALL SELECT '201605', '112033', '02' FROM dual UNION ALL SELECT '201607', '443332', '01' FROM dual ) SELECT DECODE(gb, 1, '3개월 이하' , 2, '4~6개월' , 3, '7~12개월' , 4, '12개월 초과' ) gb , COUNT(*) cnt FROM (SELECT employee_cd , CASE WHEN MAX(rn) <= 3 THEN 1 WHEN MAX(rn) <= 6 THEN 2 WHEN MAX(rn) <= 12 THEN 3 WHEN MAX(rn) > 12 THEN 4 END gb FROM (SELECT employee_cd , TO_DATE(create_ym, 'yyyymm') ym , ROW_NUMBER() OVER(PARTITION BY employee_cd ORDER BY create_ym DESC) rn FROM t WHERE cd = '02' AND create_ym <= '201611' ) WHERE TO_CHAR(ADD_MONTHS(ym, rn-1), 'yyyymm') = '201611' GROUP BY employee_cd ) a GROUP BY a.gb ORDER BY a.gb ;
아! 정말 감사합니다
그런데 마농님 쿼리를 확인해보니
201611로 조회를 하면 얘를 기준으로 이전에 04가 얼마나 연속되는지를 찾더라구요 ㅠ
제가 설명을 잘못한 부분이니 죄송하단 말씀드리겠습니다
jkson님 쿼리는 제가 DB끈이 짧다보니 이해를 못해서 ㅠ
두분 쿼리 모두 제가 수정해보고 안되서 염치불구 하고 다시 질문드립니다
다시 설명해드리면 201611로 조회를 하면 이전월 201610, 201609, 201608이 02이면
3개월 이하로 되어 카운트1이 됩니다
즉, 월분이 조회년월 201611 전월을 기준으로 연속해서 2016년 10월 9월 8월이 02이고 7월이 01이면 3개월 동안 02가 지속 되었기 때문에 3개월 이하
해당 구분에 카운트 1이 되며 다른 개월수 구분에 중복이 되어선 안됩니다
ex)12개월 초과에 카운트 1이 됬으면 다른 구분에는 포함되면 안됨
인데 201611월 전월을 기준으로 월분이 연속이며 02라는 데이터까지 연속이라는것을 찾아내려니
아주 골때리네요 ㅠ
오늘 하루종일 이것저것 써보는데 되지않아 답답하네요..
제가 만든 쿼리는 전체 데이터 기준으로 연속된 월의 카운트를 구하는 거라 요청하신 내용과 다릅니다^^;
결과 예시가 적어주신 기초 데이터와 달라서 제 생각대로 만들었어요.
(기초 데이터로 조회했을 때 결과를 적어주셨으면 더 정확하게 답변 달아드렸을텐데 말이죠.
제 형편없는 이해력이 물론 제일 큰 원인이겠지만요-0-)
02인 데이터가 1월, 2월, 3월, 4월, 7월, 8월, 10월, 11월 이렇게 있으면
(1월, 2월, 3월, 4월), (7월, 8월), (10월, 11월)
이렇게 묶어서 3~6개월 : 1, 3개월이하 : 2 이렇게 나오는 쿼리예요.
아.. 그리고 3개월이하면 3개월까지 포함인 거죠? 3~6개월에 3이 또 있길래..ㅋㅋ
아! 피드백 감사드립니다!
jkson님 쿼리도 지금 분석하면서 공부중입니다 ㅎ 감사드립니다!
가상 테이블에서는 저렇게 하는게 맞는데
제 DB에서 작성하신 쿼리의 케이스문 바로 밑의 서브쿼리를 조회 해보니
사원번호 년월 RN카운트
102001 2015-10-01 1
102001 2015-09-01 2
112002 2016-10-01 1
112002 2015-12-01 2
112002 2015-11-01 3
112002 2015-06-01 4
112002 2015-05-01 5
112002 2015-03-01 6
112002 2014-09-01 7
112002 2013-01-01 8
112002 2012-11-01 9
112002 2012-03-01 10
112002 2012-02-01 11
112002 2011-07-01 12
이런식으로 월분이 연속되지않게 월분관계 없이 02만 연속인지 체크를 하더군요
10월에서 거꾸로 순서대로 가면서 02인지 체크해서 아니면 거기서 스탑!하고 싶은데
RANGE도 써보고 했는데 마음대로 안되네요... 조건절만 뭔가 건드려주면 될거 같기도 하고..
바쁘실텐데 거듭 질문드려 죄송합니다
서브쿼리 결과만 보고 잘못 판단하신 듯 하네요?
서브쿼리에서 rn 을 붙인 결과가 최종결과가 아니죠.
그다음 add_month 조건절로 최종결과물을 추출합니다.
사원번호 년월 RN TO_CHAR(ADD_MONTHS(ym, rn), 'yyyymm')
102001 2015-10-01 1 201511
102001 2015-09-01 2 201510
112002 2016-10-01 1 201611 <--- 최종결과에 포함
112002 2015-12-01 2 201602
112002 2015-11-01 3 201602
112002 2015-06-01 4 201510
112002 2015-05-01 5 201510
112002 2015-03-01 6 201509
112002 2014-09-01 7 201504
112002 2013-01-01 8 201309
112002 2012-11-01 9 201308
112002 2012-03-01 10 201301
112002 2012-02-01 11 201301
112002 2011-07-01 12 201207
마농님 답변대로 해도 원하는 결과가 안 나오신다면
원하시는 바를 잘못 설명하셨든지
아직 쿼리를 제대로 이해 못 하신 게 아닐까요?
WITH t AS
(
SELECT '201611' create_ym, '112033' employee_cd, '02' cd FROM dual
UNION ALL SELECT '201610', '112033', '02' FROM dual
UNION ALL SELECT '201609', '112033', '02' FROM dual
UNION ALL SELECT '201608', '112033', '02' FROM dual
UNION ALL SELECT '201608', '443332', '01' FROM dual
UNION ALL SELECT '201607', '112033', '01' FROM dual
UNION ALL SELECT '201605', '112033', '02' FROM dual
UNION ALL SELECT '201607', '443332', '01' FROM dual
)
SELECT employee_cd
, ym
, rn
, TO_CHAR(ADD_MONTHS(ym, rn), 'yyyymm') fg
FROM (SELECT employee_cd
, TO_DATE(create_ym, 'yyyymm') ym
, ROW_NUMBER() OVER(PARTITION BY employee_cd ORDER BY create_ym DESC) rn
FROM t
WHERE cd = '02'
AND create_ym < '201611'
)
이 쿼리 결과를 보세요.
역순으로 순번을 준 rn 값과 ym 을 더한 값이 201611이 나온다는 것은
중간에 빈 달이 없다는 것이고 연속된 데이터라는 거죠.
EMPLOYEE_CD YM RN FG
112033 2016-10-01 1 201611 -> 연속
112033 2016-09-01 2 201611 -> 연속
112033 2016-08-01 3 201611 -> 연속
112033 2016-05-01 4 201609 -> 역순으로 4번째인 201605가 4를 더하니 201609가 나왔으므로
3번째 값인 201608과 4번째 값인 201605는 이어진 값이 아님
이렇게 11월 이전에 02값을 가진 이어진 값을 찾는 쿼리예요.
원하시는 내용이 이게 맞나요?