1:n 조인 질문요 0 9 1,569

by 앗싸 [2017.01.17 16:12:11]


사원정보, 어학점수, 근무평가, 경력사항,  자격증, 발령사항 테이블을 조인 하려고 합니다.

물로 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개는 잘 되는데 그 이상 하면 안되네요. 답변 부탁 드립니다.

by 겸댕2후니 [2017.01.17 17:22:25]

테이블 3개는 잘 되는데 그 이상 하면 안되네요.

-> 이러한 내용말고, 정확히 문제가 되는 쿼리/결과를 올려주세요.


by 앗싸 [2017.01.17 18:28:48]

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건으로 나와야 하는데 생각 데로 나오지 않습니다.

    


by 마농 [2017.01.18 08:51:57]
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
;

 


by 랑에1 [2017.01.18 09:46:30]
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
조인은 아니지만..

 


by 앗싸 [2017.01.18 10:31:54]

join 으로는 안되나요?

질문에 올린 사원정보 테이블은 이해를 돕기 이해 간단하게 올렸는데

실질적으로는 사원정보 컬럼이 많고 향후 늘어 날수 있어서요.


by 랑에1 [2017.01.18 10:41:19]

꼭 join으로 하셔야하는 이유가 있으신가요?

컬럼이 늘어난다고 꼭 조인으로 해야할 이유는 없을 것 같은데요?

마농님이 답변해주신대로 하시면 될텐데..


by 마농 [2017.01.18 10:48:05]

조인도 가능합니다만
계속 연달아서 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)
;

 


by 앗싸 [2017.01.18 11:17:57]

답변 감사합니다.

특정사원 클릭 하면, 해당 사원에 대한 인사정보 관련 테이블 모두를 한번에

조회 하여 화면에 출력 할려고 했습니다

여러번 서버에 접속 하여 데이터 가져오는게 좋지 않을 거 같아서요.

 

답변 주신 마뇽님, 겸댕2후니, 랑에1 감사,감사 합니다.

 


by 마농 [2017.01.18 14:12:25]
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
;

 

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