다음 세 개의 테이블이 있습니다.
[USER]
USER_ID(PK) | USER_NAME | DEPT_ID | DEPT_NAME |
lee1 | 이일 | 100 | 정치부 |
lee2 | 이이 | 200 | 역사부 |
lee3 | 이삼 | 300 | 경제부 |
lee4 | 이사 | 100 | 정치부 |
lee5 | 이오 | 200 | 역사부 |
lee6 | 이륙 | 600 | 과학부 |
[DEPT]
DEPT_ID | DEPT_NAME | DEPT_ORDER |
100 | 정치부 | 1 |
200 | 역사부 | 2 |
300 | 경제부 | 3 |
400 | 수학부 | 4 |
500 | 체육부 | 5 |
600 | 과학부 | 6 |
[TEST_RESULT]
TEST_SEQ | RESULT_SEQ | USER_ID | USER_NAME | DEPT_ID | DEPT_NAME | TOTAL_SCORE |
1 | 1 | lee1 | 이일 | 100 | 정치부 | 90 |
1 | 2 | lee6 | 이륙 | 600 | 과학부 | 80 |
2 | 1 | lee1 | 이일 | 100 | 정치부 | 90 |
3 | 1 | lee4 | 이사 | 100 | 정치부 | 100 |
1 | 3 | lee5 | 이오 | 200 | 역사부 | 70 |
2 | 2 | lee2 | 이이 | 200 | 역사부 | 80 |
결과로 바라는 것은
특정 시험(TEST_SEQ) 참여현황 페이지 모든 USER를 뿌려주면서 참여 여부(JOIN_YN)을 보여주는 것입니다.
그리고 검색 조건에 따라 리스트를 다시 뿌려주는 것입니다.
현재 제가 짠 SQL은 다음과 같습니다.
SELECT ROW_NUMBER() OVER(ORDER BY DEPT_ORDER ASC) RN, TEST_SEQ, RESULT_SEQ, DEPT_ID, DEPT_NAME, USER_ID, USER_NAME, NVL(JOIN_YN, 'N') AS JOIN_YN, TOTAL_SCORE FROM (SELECT NULL AS TEST_SEQ, NULL AS RESULT_SEQ, D.DEPT_ID, D.DEPT_NAME, D.DEPT_ORDER, U.USER_ID, U.USER_NAME, "" AS JOIN_YN, NULL AS TOTAL_SCORE FROM USER U, DEPT D WHERE U.USER_STAT = 'A' AND D.DEPT_ID = U.DEPT_ID AND NOT EXISTS ( SELECT 1 FROM TEST_RESULT X WHERE U.USER_ID = X.USER_ID ) UNION SELECT T.TEST_SEQ, T.RESULT_SEQ, T.USER_ID, T.USER_NAME, D.DEPT_ID, D.DEPT_NAME, D.DEPT_ORDER, DECODE(U.USER_ID, T.USER_ID, 'Y', 'N') AS JOIN_YN, T.TOTAL_SCORE FROM TEST_RESULT T, USER U, DEPT D WHERE T.USER_ID = U.USER_ID AND T.DEPT_ID = D.DEPT_ID ) WHERE TEST_SEQ = 1 OR TEST IS NULL
여기까지가 기본 쿼리구요
페이지에서 부서나 사용자, 참여여부 등으로 검색을 할 경우 전체쿼리 뒤에 AND로 쿼리를 덧 붙이는 방식입니다.
근데 결과가 기대와 달리 나오네요.
[기본 쿼리 결과 (TEST_SEQ = 1)]
TEST_SEQ | RESULT_SEQ | USER_ID | USER_NAME | DEPT_ID | DEPT_NAME | JOIN_YN | TOTAL_SCORE |
1 | 1 | lee1 | 이일 | 100 | 정치부 | Y | 90 |
lee4 | 이사 | 100 | 정치부 | N | |||
1 | 3 | lee5 | 이오 | 200 | 역사부 | Y | 70 |
lee2 | 이이 | 200 | 역사부 | N | |||
lee3 | 이삼 | 300 | 경제부 | N | |||
1 | 2 | lee6 | 이륙 | 600 | 과학부 | Y | 80 |
결과: 기존 검색조건(TEST_SEQ = 1)에 (AND DEPT_ID = '100') 추가시
TEST_SEQ | RESULT_SEQ | USER_ID | USER_NAME | DEPT_ID | DEPT_NAME | JOIN_YN | TOTAL_SCORE |
1 | 1 | lee1 | 이일 | 100 | 정치부 | Y | 90 |
lee4 | 이사 | 100 | 정치부 | ||||
1 | 3 | lee5 | 이오 | 200 | 역사부 | Y | 70 |
1 | 2 | lee6 | 이륙 | 600 | 과학부 | Y | 80 |
결과는 첫번째 줄만 나와야 하는데, DEPT_ID 검색 조건이 제대로 안 먹히네요..
UNION을 썼는데 제가 놓치는 부분이 있는 것 같기도 하고...
지금 해결책은 A UNION B 상태에서 A, B 쿼리에 똑깥이 검색 조건을 걸어야 합니다.
쿼리와 서버단 코딩이 같은 작업을 두 번 해야하니 지저분해지네요.
해결 법좀 알려주세요..ㅜㅜ
UNION 안써도 될거 같은데요..
그리고 구지 쓴다면 UNION ALL로 하셔도 무방할 듯 합니다.
SELECT T.TEST_SEQ, T.RESULT_SEQ, U.USER_ID, U.USER_NAME, D.DEPT_ID, D.DEPT_NAME, D.DEPT_ORDER, DECODE(T.USER_ID, NULL, 'N', 'Y') AS JOIN_YN, T.TOTAL_SCORE FROM USER U, DEPT D, TEST_RESULT T WHERE U.DEPT_ID = D.DEPT_ID AND U.USER_ID = T.USER_ID(+) ;
--[기본 쿼리 결과 (TEST_SEQ = 1)] SELECT T.TEST_SEQ, T.RESULT_SEQ, U.USER_ID, U.USER_NAME, D.DEPT_ID, D.DEPT_NAME, D.DEPT_ORDER, DECODE(T.USER_ID, NULL, 'N', 'Y') AS JOIN_YN, T.TOTAL_SCORE FROM USER U, DEPT D, TEST_RESULT T WHERE U.DEPT_ID = D.DEPT_ID AND U.USER_ID = T.USER_ID(+) AND (T.TEST_SEQ = 1 OR T.TEST_SEQ IS NULL) ; --기존 검색조건(TEST_SEQ = 1)에 (AND DEPT_ID = '100') 추가시 SELECT T.TEST_SEQ, T.RESULT_SEQ, U.USER_ID, U.USER_NAME, D.DEPT_ID, D.DEPT_NAME, D.DEPT_ORDER, DECODE(T.USER_ID, NULL, 'N', 'Y') AS JOIN_YN, T.TOTAL_SCORE FROM USER U, DEPT D, TEST_RESULT T WHERE U.DEPT_ID = D.DEPT_ID AND U.USER_ID = T.USER_ID(+) AND (T.TEST_SEQ = 1 OR T.TEST_SEQ IS NULL) AND D.DEPT_ID = '100' ;
오 결과 잘 나오네요 감사합니다.
근데 실제로는 또 중요한 조건이 하나 더 있는데 이거 해보려니 어렵네요.
USER 테이블에 상태 컬럼(재직, 전출, 퇴직 등..)이 하나 더 있습니다.
그리고 TEST_RESULT는 실제로 TEST 테이블과 관계가 맺어져 있는데요.
TEST 하나당 기간이 잡혀져 있어요.
그 기간 안에 참여한 사람은 TEST_RESULT에 들어가는데
나중에 위의 쿼리를 통해 참여 현황을 조회할 때 USER의 상태가 재직 중이 아니어도 TEST_RESULT에 존재하는 USER이면 리스트에 떠야되요.
단순히 AND U.STAT = '재직' 으로 하면 TEST_RESULT에서도 걸러지게 되더라구요.
처음에 그래서 조인으로 안하고 UNION을 썼었던 건데.. 현재 쿼리 구조에서도 가능할까요?
SELECT t.test_seq , t.result_seq , u.user_id , u.user_name , u.dept_id , d.dept_name , t.total_score FROM user u , dept d , test_result t WHERE u.dept_id = d.dept_id AND u.user_stat = 'A' AND u.dept_id = 100 AND u.user_id = t.user_id(+) AND t.test_seq(+) = 1 ORDER BY u.dept_id , t.test_seq , t.result_seq , u.user_id ;