본문 바로가기

DB

SQL JOIN

테이블간 조인에 대해 알아봅시다.

여기서 테이블이란, 테이블 뿐만이 아니라, 아주 폭넓은 의미가 될 수 있습니다.
이럴테면, 뷰가 될수도 있고, 테이블리턴함수에 의한 row들의 결과물이 될수도 있고,
SELECT 에 의한 row 들의 결과물이 될수도 있습니다. 즉, record 형태로 보여질수
있는 모든 결과물이 올 수가 있습니다.

이 조인 방법에는 3가지가 있습니다.
INNER JOIN, OUTER JOIN, SELF JOIN 인데, 각각 사용목적이 틀립니다.
때에 따라선 똑같은 결과가 나올수 있지만, 처리방식에 있어서 차이가 있으니
적절한 곳에 적절한 방식을 사용해야 할 것입니다.

본 결과물은 PostgreSQL 7.4.6 에서 시행되었습니다.

주의: 다 쓰고 보니 '도시' 라는 테이블명과 날씨테이블안의 '도시' 컬럼명이
동일하여 해갈릴수 있습니다. 알아서..잘 보시길..

mydb=> select * from 날씨;
     도시     | 최소 | 최대
--------------+------+------
 샌프란시스코 |   46 |   50
 샌프란시스코 |   43 |   57
 라스베가스   |   37 |   54
(3 rows)

mydb=> select * from 도시;
     이름    
--------------
 샌프란시스코
 로스엔젤레스
(2 rows)

잘 보시면 날씨 테이블에서 도시이름에 도시테이블에 없는 라스베가스가 있으며,
도시테이블에서도 날씨테이블에는 없는 로스엔젤레스가 있습니다.
각 조인별 결과를 유심히 보면, 그 차이점을 알 수 있습니다.

만일 두 테이블이 Foriegn Key 등에 의해 도시이름이 완전히 동일할 경우에는
inner join 과 outer join 의 결과는 다르지 않을 것입니다.
이때, 두가지 방법에서의 속도문제를 거론하고자 한다면, 각자 테스트 해보시길 바랍니다.

참고로 위의 테이블 구조는 테이블 조인을 위한 아주 기본적인 구조이므로,
실제로는 많은 컬럼이 존재하게 될지도 모릅니다.
날씨 테이블의 경우 풍속, 강수량, 습도 등등을 포함할수 있으며, 도시의 경우
그 도시의 면적, 인구, 인구밀도 등등이 함꼐 올 수 있지요.
이럴 경우 FK 로 두 테이블의 도시명이 동일해질수도 있지만, 얼마던지 달라질 수도
있습니다. 조인시 그점을 유념하셔야 합니다.


INNER JOIN 방법입니다.

mydb=> select w.*, c.* from 날씨 w, 도시 c where w.도시 = c.이름;
     도시     | 최소 | 최대 |     이름    
--------------+------+------+--------------
 샌프란시스코 |   46 |   50 | 샌프란시스코
 샌프란시스코 |   43 |   57 | 샌프란시스코
(2 rows)

여기서 보시면 날씨테이블의 도시이름과 도시테이블의 도시이름이 같은것만 나옵니다.
라스베가스라던지 로스엔젤레스는 전혀 나오지 않는다는 것이지요. 가장 일반적인
형태입니다.

참고로

mydb=> select * from 날씨 INNER JOIN 도시 on (날씨.도시 = 도시.이름);
     도시     | 최소 | 최대 |     이름    
--------------+------+------+--------------
 샌프란시스코 |   46 |   50 | 샌프란시스코
 샌프란시스코 |   43 |   57 | 샌프란시스코
(2 rows)

이것 역시 위와 동일한 결과를 가져옵니다. 이런 형태의 INNER JOIN 은 거의
사용하지 않는 방법입니다만.. 다음의 OUTER 조인의 형태와 동일하기 때문에 언급한
것 뿐입니다. 그렇다고 틀린구문이라고 볼수는 없습니다.

그럼 이제 OUTER JOIN 을 보도록 하죠.

mydb=> select * from 날씨 LEFT OUTER JOIN 도시 on (날씨.도시 = 도시.이름);
     도시     | 최소 | 최대 |     이름    
--------------+------+------+--------------
 라스베가스   |   37 |   54 |
 샌프란시스코 |   46 |   50 | 샌프란시스코
 샌프란시스코 |   43 |   57 | 샌프란시스코
(3 rows)

보시는 보와 같이 INNER JOIN 과는 다른 결과를 가져옵니다.
라스베가스 라는 것이 하나 더 있지요.
그리고 이름컬럼에 보면 라스베가스에 해당하는 도시테이블에서 데이타가 없으므로
NULL 값이 나옵니다(비어 있습니다.)

위에서 left outer join 에서 outer 는 생략가능합니다. 즉

mydb=> select * from 날씨 LEFT JOIN 도시 on (날씨.도시 = 도시.이름);
     도시     | 최소 | 최대 |     이름    
--------------+------+------+--------------
 라스베가스   |   37 |   54 |
 샌프란시스코 |   46 |   50 | 샌프란시스코
 샌프란시스코 |   43 |   57 | 샌프란시스코
(3 rows)


결과가 같으므로 outer 는 생략하도록 하겠습니다.

참고사항으로 OUTER JOIN 에는 흔히들 LEFT 만 있다고 생각하는데, LEFT 외에도
RIGHT, FULL 도 있습니다.

mydb=> select * from 날씨 RIGHT JOIN 도시 on (날씨.도시 = 도시.이름);
     도시     | 최소 | 최대 |     이름    
--------------+------+------+--------------
              |      |      | 로스엔젤레스
 샌프란시스코 |   46 |   50 | 샌프란시스코
 샌프란시스코 |   43 |   57 | 샌프란시스코
(3 rows)

mydb=> select * from 날씨 FULL JOIN 도시 on (날씨.도시 = 도시.이름);
     도시     | 최소 | 최대 |     이름    
--------------+------+------+--------------
 라스베가스   |   37 |   54 |
              |      |      | 로스엔젤레스
 샌프란시스코 |   46 |   50 | 샌프란시스코
 샌프란시스코 |   43 |   57 | 샌프란시스코
(4 rows)

어때요? 결과가 또 다르죠?

그러므로 INNER 를 쓸 것인지 OUTER 를 쓸것인지.. LEFT, RIGHT 혹은 FULL 을 쓸
것인지..상황에 따라 달라지므로 해당 방법을 적절한 곳에 사용해야 겠지요.
일반적으로 OUTER 조인방식은 특별한 경우가 아니라면 잘 사용하지 않는 방식이라고
하는군요. 아울러 아래에 소개할 SELF JOIN 역시 왠만하면 사용하지 말라고 하더군요.
(필요하다면 사용해야겠지만..)

이제 마지막 조인 방법인 SELF JOIN 을 봅시다.

mydb=> select w1.*, w2.* from 날씨 w1, 날씨 w2
mydb-> where w1.최소 < w2.최소 and w1.최대 > w2.최대;
     도시     | 최소 | 최대 |     도시     | 최소 | 최대
--------------+------+------+--------------+------+------
 샌프란시스코 |   43 |   57 | 샌프란시스코 |   46 |   50
 라스베가스   |   37 |   54 | 샌프란시스코 |   46 |   50
(2 rows)

출처 : http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=36105&sca=&sfl=wr_subject%7C%7Cwr_content&stx=%C5%D7%C0%CC%BA%ED%B0%A3+%C1%B6%C0%CE&sop=and