사원정보, 어학점수, 근무평가, 경력사항, 자격증, 발령사항 테이블을 조인 하려고 합니다.
물로 union 으로 할 수도 있지만 사원정보 table 컬럼이 너무 많고, 그외 많은 테이블과 조인을 해야 하며,
컬럼이 추가시 또 쿼리를 수정 해야 하는 번거로움이 있어 Join 을 사용 하려고 합니다.
모든 테이블이 사원테이블 과 1 : n 입니다.
A Table(사원정보)
ID Name
201701 가
201702 나
201703 다
201704 라
201705 마
B Table(어학점수)
ID Score
201701 90
201701 100
201702 30
201703 70
201704 60
201705 60
C Table(근무평가)
201701 AAA
201701 BBB
201702 CCC
201705 BBB
201705 CCC
D Table(경력사항)
201701 Z회사
201703 A회사
201703 B회사
201703 C회사
201705 D회사
201705 Z회사
201702 G회사
E Table(발령사항)
201701 A팀
201701 B팀
201701 C팀
201701 D팀
201701 E팀
201702 G팀
201702 F팀
201702 H팀
원하는 결과
ID "201701" 조회시
====================================================
201701 가 201701 90 201701 AAA 201701 Z회사 201701 A팀
201701 100 201701 BBB 201701 B팀
201701 C팀
201701 D팀
201701 E팀
===================================================
테이블 3개는 잘 되는데 그 이상 하면 안되네요. 답변 부탁 드립니다.
with a as
(
select '1' id, '가' name from dual
)
, b as
(
select '3' id, 90 score from dual union all
select '2', 100 from dual union all
select '2', 30 from dual union all
select '3', 70 from dual union all
select '3', 60 from dual union all
select '5', 60 from dual
)
, c as
(
select '1' id, 'AAA' grade from dual union all
select '1', 'BBB' from dual union all
select '4', 'CCC' from dual union all
select '5', 'BBB' from dual union all
select '5', 'CCC' from dual
)
, D as
(
select '1' id, 'A팀' team from dual union all
select '1', 'B팀' from dual union all
select '1', 'C팀' from dual union all
select '3', 'H팀' from dual union all
select '3', 'A팀' from dual union all
select '3', 'B팀' from dual union all
select '1', 'H팀' from dual union all
select '1', 'G팀' from dual union all
select '1', 'K팀' from dual union all
select '2', 'A팀' from dual
)
, E as
(
select '3' id, 'A회사' COM from dual union all
select '3', 'B회사' from dual union all
select '3', 'C회사' from dual union all
select '3', 'D회사' from dual union all
select '1', 'F회사' from dual
)
SELECT X.ID, Y.SCORE, Y.GRADE, Y.Team, Y.COM
FROM A X
LEFT OUTER JOIN
(
SELECT COALESCE(B.ID, C.ID, D.ID, E.ID) ID, B.SCORE, C.GRADE, D.Team, E.COM
FROM
(SELECT ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ROWNUM) RNUM, ID, SCORE FROM B) B
FULL OUTER JOIN
(SELECT ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ROWNUM) RNUM, ID, GRADE FROM C) C
ON (B.ID = C.ID AND B.RNUM = C.RNUM)
FULL OUTER JOIN
(SELECT ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ROWNUM) RNUM, ID, Team FROM D) D
ON (B.ID = D.ID AND B.RNUM = D.RNUM)
FULL OUTER JOIN
(SELECT ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ROWNUM) RNUM, ID, COM FROM E) E
ON (B.ID = E.ID AND B.RNUM = E.RNUM)
) Y
ON (X.ID = Y.ID)
ORDER BY 1,2,3
아래 처럼 결과가 나옵니다.
===========================
ID SCORE GRADE TEAM COM
1 AAA
1 BBB
1 F회사
1 C팀
1 B팀
1 K팀
1 H팀
1 A팀
1 G팀
원하는 결과는 아래 처럼 나왔으면 합니다.
===========================
ID SCORE GRADE TEAM COM
1 AAA C팀
1 BBB B팀
1 K팀 F회사
1 H팀
1 A팀
1 G팀
ID "1" 이 있는 테이블 별 갯수가
B (0), C(2), D(6), E(1) 이므로, 최고 많은 테이블이 6건 이니
조인하여 나올수 있는 건수가 6건으로 나와야 하는데 생각 데로 나오지 않습니다.
SELECT id , rn , MIN(name ) name , MIN(score) score , MIN(grade) grade , MIN(team ) team , MIN(com ) com FROM (SELECT id, name, score, grade, team, com , ROW_NUMBER() OVER(PARTITION BY id, gb ORDER BY 1) rn FROM (SELECT 1 gb, id, name, null score, null grade, null team, null com FROM a UNION ALL SELECT 2, id, null name, score, null grade, null team, null com FROM b UNION ALL SELECT 3, id, null name, null score, grade, null team, null com FROM c UNION ALL SELECT 4, id, null name, null score, null grade, team, null com FROM d UNION ALL SELECT 5, id, null name, null score, null grade, null team, com FROM e ) WHERE id = 1 ) GROUP BY id, rn ORDER BY id, rn ;
SELECT * FROM ( SELECT * FROM ( SELECT A.*, '1' gb, ROW_NUMBER() OVER(PARTITION BY id ORDER BY Name) rn FROM A UNION ALL SELECT B.*, '2' gb, ROW_NUMBER() OVER(PARTITION BY id ORDER BY Score) rn FROM B UNION ALL SELECT C.*, '3' gb, ROW_NUMBER() OVER(PARTITION BY id ORDER BY grade) rn FROM C UNION ALL SELECT D.*, '4' gb, ROW_NUMBER() OVER(PARTITION BY id ORDER BY team) rn FROM D UNION ALL SELECT E.*, '5' gb, ROW_NUMBER() OVER(PARTITION BY id ORDER BY com) rn FROM E ) -- WHERE id = '201701' ) PIVOT (MIN(Name) FOR gb IN (1 Name, 2 Score, 3 Grade, 4 Team, 5 Com)) ORDER BY id, rn 조인은 아니지만..
조인도 가능합니다만
계속 연달아서 FULL OUTER JOIN 을 해야 합니다.
조인 조건은 복잡해 지구요.
정확한 연결관계를 갖는 집합끼리의 조인이라면 조인이 많아도 문제가 없지만
연결관계를 억지로 맺는 조인인데다가.
심지어는 FULL OUTER 조인인데다가.
심지어는 다대다 관계 조인입니다.
다대다 관계 조인은 1차 조인만 해야지 2차 3차 조인하면 상당히 무겁습니다.
조인보다는 UNION 방법이 더 쉽고 성능도 더 좋을 것으로 생각됩니다.
또한 위와 같이 상관 없는 자료를 한번에 뽑으려고 하는 의도가 뭔지 생각해 볼 필요가 있습니다.
쿼리로 모든걸 다 하려고 하지 마세요.
위와 같은 경우에는 차라리 각각 쿼리 5번 돌리고 프로그램단에서 화면 구성하는게 낫습니다.
SELECT * FROM (/* id 조건 rn 서브쿼리 */) a FULL OUTER JOIN (/* id 조건 rn 서브쿼리 */) b ON b.rn = a.rn FULL OUTER JOIN (/* id 조건 rn 서브쿼리 */) c ON c.rn = COALESCE(a.rn, b.rn) FULL OUTER JOIN (/* id 조건 rn 서브쿼리 */) d ON d.rn = COALESCE(a.rn, b.rn, c.rn) FULL OUTER JOIN (/* id 조건 rn 서브쿼리 */) e ON e.rn = COALESCE(a.rn, b.rn, c.rn, d.rn) ORDER BY COALESCE(a.rn, b.rn, c.rn, d.rn, e.rn) ;
SELECT lv , id , name , score , grade , team , com FROM (SELECT LEVEL lv FROM dual CONNECT BY LEVEL <= (SELECT MAX(cnt) FROM (SELECT COUNT(*) cnt FROM b WHERE id = 1 UNION ALL SELECT COUNT(*) FROM c WHERE id = 1 UNION ALL SELECT COUNT(*) FROM d WHERE id = 1 UNION ALL SELECT COUNT(*) FROM e WHERE id = 1 ) ) ) z LEFT OUTER JOIN (SELECT 1 rn, id, name FROM a WHERE id = 1) a ON z.lv = a.rn LEFT OUTER JOIN (SELECT ROWNUM rn, score FROM b WHERE id = 1) b ON z.lv = b.rn LEFT OUTER JOIN (SELECT ROWNUM rn, grade FROM c WHERE id = 1) c ON z.lv = c.rn LEFT OUTER JOIN (SELECT ROWNUM rn, team FROM d WHERE id = 1) d ON z.lv = d.rn LEFT OUTER JOIN (SELECT ROWNUM rn, com FROM e WHERE id = 1) e ON z.lv = e.rn ORDER BY lv ;