쿼리좀 도와주세요~~~ 0 12 1,585

by wenzie [SQL Query] [2013.08.14 16:18:55]


lesson table (교육테이블)
service_no member_no lesson_date
123 11111 20130101
123 11111 20130203
123 11111 20130206
123 11111 20130220
3333 22222 20130201
3333 22222 20130301
222 22222 20130201

service_no : 서비스 번호
member_no : 회원번호
lesson_date : 교육일


service_log Table (서비스이력테이블)
service_no status status_date
123 EDUST00001 20130120
123 EDUST00001 20130204
123 EDUST00004 20130221
3333 EDUST00001 20130209
3333 EDUST00002 20130309
222 EDUST00003 20130201

service_no : 서비스 번호
status : 상태 (EDUST00001 ~ EDUST00012)
status_date : 상태변경일


제가 원하는 결과물

service_no sdate(교육시작) edate(교육끝)
123 20130101 20130119
123 20130203 20130203
123 20130206 20130220
3333 20130201 20130208
3333 20130301 20130930
222 20130201 20130930


11111회원의 교육기간은 20130101 ~ 20130220 입니다. (lesson_date min ~ max까지가 교육기간입니다.)
그런데 service_log 테이블의 상태(status)에 따라서 기간이 나뉘어 져야 합니다

status 가 EDUST00001,EDUST00004,EDUST00011,EDUST00012 일경우
해당 상태값이 등록된 날짜(status_date) 하루전까지가 교육기간이됩니다.

위 데이터를 예로 들면

11111 회원의 경우 교육시작이 20130101 이고 상태(EDUST00001)가 바뀐 날짜는 20130120 입니다.
그러므로 11111 회원의 첫번째 교육기간은 20130101 ~ 20130119 ( 상태값이 등록된 날짜(20130120 ) -1 )이고

11111 회원의 두번째 교육기간은 상태값이 등록된 날짜(20130120)와 가장근접한 교육일(lesson_date )이
두번째 교육 시작일(20130203)이 됩니다. 그리고 상값이 등록된 날짜가 20130204 이므로 하루를빼면
두번째 교육 기간은 20130203 ~ 20130203 입니다.


11111회원의 세번째 교육기간은 20130206 ~ 20130220 입니다.



22222 회원의 교육일은 (20130201 ~ 20130301) 인데 상태값에 EDUST00001 이 있으므로 교육기간을 또 분리해야 합니다.

교육시작일은 20130201 이고 상태(EDUST00001)가 바뀐 날짜는 20130209입니다.
그러므로 22222회원의 첫번째 교육기간은 20130101 ~ 20130208( 상태값이 등록된 날짜(20130209) -1 )이고

22222 회원의 두번째 교육기간은 상태값이 등록된 날짜(20130208)와 가장근접한 교육일(lesson_date )이
두번째 교육 시작일(20130301)이 됩니다. 그리고 상값이 등록된 날짜가 20130309 이지만
EDUST00001,EDUST00004,EDUST00011,EDUST00012 값에 해당되지 않기때문에 상태일을 무시하고 특정일까지가
교육기간이 됩니다. 샘플의 특정일은 20130931로 했습니다.

22222 회원의 두번째 교육 기간은 20130301~ 20130930 입니다

마지막 저장된 상태값이 EDUST00001,EDUST00004,EDUST00011,EDUST00012이 아니라면 특정일까지가
교육기간이 됩니다.


ㅜㅜㅜ 아오 복잡해...이해를 하셨는지 모르겠습니다.


2일째 고민중입니다.

궁금하신 사항 있으시면 말씀주세요~~ㅜㅜ 이게 가능은 한건가요~~~













by 아린 [2013.08.14 17:01:12]
WITH lesson(service_no, member_no, lesson_date) AS(
SELECT '123',  '11111', '20130101' FROM dual UNION ALL
SELECT '123',  '11111', '20130203' FROM dual UNION ALL
SELECT '123',  '11111', '20130206' FROM dual UNION ALL
SELECT '123',  '11111', '20130220' FROM dual UNION ALL
SELECT '3333', '22222', '20130201' FROM dual UNION ALL
SELECT '3333', '22222', '20130301' FROM dual UNION ALL
SELECT '222',  '22222', '20130201' FROM dual
), service_log(service_no, status, status_date) AS(
SELECT '123',  'EDUST00001', '20130120' FROM dual UNION ALL
SELECT '123',  'EDUST00001', '20130204' FROM dual UNION ALL
SELECT '123',  'EDUST00004', '20130221' FROM dual UNION ALL
SELECT '3333', 'EDUST00001', '20130209' FROM dual UNION ALL
SELECT '3333', 'EDUST00002', '20130309' FROM dual UNION ALL
SELECT '222',  'EDUST00003', '20130201' FROM dual
)
SELECT service_no, status
     , (SELECT MIN(lesson_date)
          FROM lesson l 
         WHERE l.service_no = s.service_no
           AND l.lesson_date >= s.p_status_date) sdt
     , CASE WHEN status IN ('EDUST00001', 'EDUST00004'
                          , 'EDUST00011', 'EDUST00012')  
            THEN TO_CHAR(TO_DATE(status_date, 'yyyymmdd') -1, 'yyyymmdd')
            ELSE '20130930'
       END edt                     
  FROM (SELECT service_no, status, status_date
             , NVL(LAG(status_date) OVER(PARTITION BY service_no
               ORDER BY status_date), '20000101') p_status_date
          FROM service_log
        ) s 

by wenzie [2013.08.15 09:41:52]
어제 정신이없어서 이제야 글올리네요 ^^ 답변감사합니다 큰도움 되었습니다

by 마농 [2013.08.14 17:54:45]

22222 회원은 마지막이 9/30 까지인데. 왜 11111 회원은 2/20 에서 끝나죠?
11111 도 2/20~9/30이 있어야 하는것 아닌가요?


by wenzie [2013.08.14 18:03:43]
마농님 오셨군요..ㅜㅜ

마지막 저장된 상태값이 EDUST00001,EDUST00004,EDUST00011,EDUST00012이 아니라면 특정일까지가 교육기간이 됩니다.

11111회원은 마지막 상태가 EDUST00004로 끝나서 9/30일까지 할 필요가 없습니다.^^

by 마농 [2013.08.14 18:08:41]
만약 11111의 4번째 자료가 2/20 일이 아닌 2/21일이라면
이런 경우가 발생 가능한가요? 이런 경우 결과는 어떻게 나와야 하나요?

by wenzie [2013.08.14 18:24:35]

만약 11111의 4번째 자료가 2/20 일이 아닌 2/21일이라면
이런 경우가 발생 가능한가요? 이런 경우 결과는 어떻게 나와야 하나요?

가능은 합니다.. 교육일지를 먼저쓰고 그다음에 상태변경을 해버릴 경우가 있을 수도 있는데요

이런경우는 극히 드물게 발생 할듯 하구요

혹 발생했다 하더라도 그건 작성한 사람이 잘못 작성했기 때문에 어쩔수 없을듯 합니다

1232013020620130220
이대로 나오면 될듯한데요..^^

by 마농 [2013.08.16 08:48:32]
음...
잘못 작성했기 때문에 어쩔 수 없다는 답을 듣고 싶엇던게 아니고...
제외되어야 한다면 어떤 규칙으로 제외해야 하는지를 듣고 싶었어요...
데이터가 이쁘게 (시작,종료) 짝을 이루어 들어온다면 문제 없겠지만...
오류 데이터들이 존재한다면 이에 대한 예외처리도 생각해야 합니다.
(시작-종료,시작-종료,시작) 까지만 있는 자료에서
마지막 시작을 왜 제외해야 하는지 모르겠네요.
진짜 끝난건지? 아직 진행중인지를 판단할 명확한 기준이 필요해 보이네요.
(시자, 시작-종료) 또는 (시작, 시작, 시작) 처럼 꼬인 데이터는 없는지?

by wenzie [2013.08.16 11:02:29]

아 시작을 제외 하는건 아닙니다. 제가 잘못 답변 드렸나봅니다. ^^

조금 더 설명을 하겠습니다.

일단 상태코드를 정리해 드립니다.

1.일시중단(EDUST00001)
2.시작(EDUST00002)
3.종료(EDUST00003)
4.같은지역으로 이동(EDUST00011)
5.다른지역으로 이동(EDUST00012)


EDUST00011,12의 경우는 다시는 상태를 변경 할수 없습니다.

하지만 나머지 경우들은 계속 변동이 가능합니다.

예를 들어
1.시작-일시중단-시작-종료
2.시작-종료-시작-일시중단
3.시작-종료-시작
4.시작-일시중단-시작
5.시작

요런 등등의 경우가 있는데요 더 길게 하는 경우도 있겠지요
단 일시중단중에 종료는 안되며 반대의 경우(종료-일시중단)도 일어날수 없는 경우 입니다.
반드시 시작후에 다음에 상태를 변경해야 합니다.

현재 회원교육이 시작 중이라면 특정일자까지(20130930)로 보면 됩니다.

이해 하셨는지 모르겠습니다.ㅜㅜ

궁금하신 사항있으시면 질문주세요..꼭 해야 하거든요..

마농님 및 다른 회원님들 부탁드립니다~~ㅜㅜ


by 마농 [2013.08.16 12:13:05]
숨겨 놓은 것이 하나씩 드러나는군요. ^^ 그러나, 아직 멀었네요.
최초 교육내역과 서비스이력이 왜 나누어져 있느지 모르겟네요.
상태코드 2번이 시작이라면 서비스 이력만으로 시작 종료 구간을 만들 수 있는것 아닌지요?
교육내역이라는 테이블의 날짜가 뭔 의미하는 날짜인가요? 왜 이날짜를 시작일로 볼까요?
테이블간의 연관관계가 그려지질 않네요.
최초 질문에서 점점 더 멀어지고 있습니다...

by wenzie [2013.08.16 13:02:01]

그러게요~~첫게시물 과 점점 멀어지는듯한..

괜찮습니다. 데이터만 정확히 나온다면 ..ㅎㅎ

LESSON 테이블은 교육에 관한 테이블 입니다.
LESSON_DATE는 교육을 진행한 날짜 입니다.

한회원의 교육한 날짜를 적는것이구요  다른 데이터도 물론 있지만
교육일을 뽑는것이기때문에 날짜만 적어 둔겁니다.

SERVICE_LOG 테이블은 서비스 이력으로 한 회원에 대한 서비스 상태를 체크하기 위해
만들었습니다. 한 회원이 교육서비스를 받는 동안 무슨 일이 있엇는지 알기위해서입니다.

중간에 일시중단 했는지 아니면 종료하고 다시 시작했는지 ,다른지역으로 이동을 했는지 등등을 알기위해서 입니다.

첫시작은 대기에서 시작하지만 서비스이력에는 데이터가 쌓이지 않습니다.
서비스 시작(EDUST00002)이 최초 서비스이력으로 동록되면서 교육일지를 작성할 수 있습니다.

맘같아선 네이트원격이라도 열어서 보여드리고 싶네요..ㅜㅜ


by 마농 [2013.08.16 13:41:34]

서비스 이력에 시작과 종료가 모두 들어 있다면?
부정확할수도 있는 교육 일지는 불필요 한게 아닌가 싶네요?
서비스 이력이 정확하게 들어 있다면 다음과 같이 들어 있겠지요.
service_no status status_date
123 EDUST00002 20130101 -- 시작
123 EDUST00001 20130119 -- 중단
123 EDUST00002 20130203 -- 시작
123 EDUST00001 20130203 -- 중단
123 EDUST00002 20130206 -- 시작
123 EDUST00003 20130220 -- 종료
그게 아니라 이런 저런 예외 상황들이 발생된다면...
위와 같은 테이블 구조로는 힘든게 아닌가 생각되는데요.


by wenzie [2013.08.19 11:04:04]

그렇군요.. 많은 답변 감사합니다~~~

수고하세요~

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