728x90
반응형

제 9절 조인(JOIN)


1. JOIN 개요

  두 개 이상의 테이블들을 연결 또는 결합하여 데이터를 출력하는 것을 JOIN이라고 하며, 일반적으로 사용되는 SQL 문장 상당수가 JOIN이라고 생각하면 된다. JOIN은 관계형 데이터베이스의 가장 큰 장점이면서 대표적인 핵심 기능이라고 할 수 있다.


  일반적인 경우 행들은 PRIMARY KEY(PK)나 FOREIGN KEY(FK) 값의 연관에 의해 JOIN이 성립된다. 하지만 어떤 경우에는 이러한 PK, FK의 관계가 없어도 논리적인 값들의 연관만으로 JOIN이 성립 가능하다. 


  FROM 절에 여러 테이블이 나타나더라도 SQL 에서 데이터를 처리할 떄는 단 두 개의 집합 간에만 조인이 일어난다는 것이다. FROM 절에 A, B, C 테이블이 나열되었더라도, 특정 2개의 테이블만 먼저 조인되고, 2개의 테이블이 조인되서 처리된 새로운 데이터 집합과 남은 한 개의 테이블이 다음 차례로 조인되는 것이다. 4개도 같다.


  예를 들어, A, B, C, D 4개의 테이블을 조인하고자 할 경우 옵티마이저는 ( ( (A JOIN D) JOIN C) JOIN B)와 같이 순차적으로 조인을 처리하게 된다. 



2. EQUI JOIN(동등 조인)

  동등 조인은 두 개의 테이블 간에 칼럼 값들이 서로 정확하게 일치하는 경우에 사용되는 방법으로 대부분 PK<->FK 관계를 기반으로 한다. 그러나 일반적으로 테이블 설계 시에 나타난 PK<->FK의 관계를 이용하는 것이지 반드시 이 관계로만 EQUI JOIN이 성립하는 것은 아니다. 이 기능은 계층형이나 망형 데이터베이스와 비교해서 관계형 데이터베이스의 큰 장점이다. 

  JOIN의 조건은 WHERE 절에 기술된 '=' 연산자를 사용하여 표현하게 된다. 다음은 대략적인 동등조인의 형태이다. 


SELECT 테이블1.칼럼명, 테이블2.칼럼명, ...

FROM 테이블1, 테이블2

WHERE 테이블1.칼럼명1 = 테이블2.칼럼명2;


같은 결과를 낳는 또 다른 형태는 아래와 같다.

SELECT 테이블1.칼럼명, 테이블2.칼럼명, ...

FROM 테이블1 INNER JOIN 테이블2

ON    테이블1.칼럼명1 = 테이블2.칼럼명2;


  SQL을 보면, SELECT 구문에 단순히 칼럼명이 오지 않고, "테이블명.칼럼명" 처럼 테이블명과 칼럼명이 같이 나타난다. 이렇게 특정 칼럼에 접근하기 위해 그 칼럼이 어느 테이블에 존재하는 칼럼인지를 명시하는 것은 두 가지 이유가 있다.


  먼저, 모든 테이블에 칼럼들이 유일한 이름을 가지면 괜찮지만, 중복되게 이름을 가질 경우 DBMS의 옵티마이저는 어떤 칼럼을 선택해야할지 모르기 때문에 파싱단계에서 에러가 발생한다.


  두번째, 개발자나 사용자가 조회할 데이터가 어느 테이블에 있는 칼럼을 말하는 것인지 쉽게 알 수 있게 하므로 SQL 에 대한 가독성이나 유지보수성을 높이는 효과가 있다.


  또한, 조인 조건에 맞는 데이터만 출력하는 INNER JOIN에 참여하는 대상 테이블이 N개라고 했을 떄, N개의 테이블로 부터 필요한 데이터를 조회하기 위해 필요한 JOIN 조건은 대상 테이블의 개수 - 1 개이다. 즉 N-1개가 필요하다. 예를들어 테이블이 FROM 절에 3개가 표시되어있다면 그에 대한 조인조건은 2개여야한다.


  JOIN 조건은 WHERE 절에 기술하며, JOIN은 두 개 이상의 테이블에서 필요한 데이터를 출력하기 위한 가장 기본적인 조건이다. 



 

  긴 테이블명을 계속 되풀이해서 입력하다보면 개발 생산성이 떨어지는 문제점과 함께 개발자의 실수가 발생할 가능성이 높아지는 문제가 있다. 그래서 SELECT 절에서 칼럼에 대한 ALIAS를 사용하는 것처럼 FROM 절의 테이블에 대해서도 ALIAS를 사용할 수 있다.

  JOIN 조건을 기술 할 떄 주의해야 할 사항이 있는데, 만약 테이블에 대한 ALIAS를 적용해서 SQL 문장을 작성했을 경우, WHERE 절과 SELECT 절에는 테이블명이 아닌 테이블에 대한 ALIAS를 사용해야 한다는 것이다. 

  권장사항은 아니지만 하나의 SQL 문장 내에서 유일하게 사용하는 칼럼명이라면 칼럼명 앞에 ALIAS를 붙이지 않아도 된다. 그러나 일단 별명을 사용했다면, WHERE절과 SELECT절에서 별명을 사용해야한다.


예제)

SELECT P.PLAYER_NAME 선수명, P.BACK_NO 백넘버, P.TEAM_ID 팀코드, 

T.TEAM_NAME 팀명, T.REGION_NAME 연고지

FROM PLAYER P, TEAM T

WHERE P.TEAM_ID = T.TEAM_ID;


예제) 테이블에 대한 별명을 정의했는데, SELECT 절이나 WHERE 절에서 테이블명을 사용한다면 옵티마이저가 칼럼명이 부적합하다는 에러를 파싱 단계에서 발생시킨다.


SELECT PLAYER.PLAYER_NAME 선수명, P.BACK_NO 백넘버, T.REGION_NAME 연고지,

T.TEAM_NAME 팀명

FROM PLAYER P, TEAM T

WHERE P.TEAM_ID = T.TEAM_ID

AND    P.POSITION = 'GK'

ORDER BY P.BACK_NO;


중복이 되지 않는 칼럼의 경우 별명을 사용하지 않아도 된다. 그러나 같은 이름을 가진 중복 칼럼의 경우는 테이블명이나 별명이 필수 조건이다.


SELECT REGION_NAME, TEAM_NAME, T.STADIUM_ID,

STADIUM_NAME, SEAT_COUNT

FROM    TEAM T, STADIUM S

WHERE    T.STADIUM_ID = S.STADIUM_ID;




3. Non EQUI JOIN

  Non EQUI(비등가) JOIN은 두 개의 테이블 간에 칼럼 값들이 서로 정확하게 일치하지 않는 경우에 사용된다. 비동등조인의 경우 '=' 연산자가 아닌 다른 (Between, >, >=, <, <= 등) 연산자들을 사용하여 JOIN을 수행하는 것이다.

  두 개의 테이블이 PK-FK로 연관 관계를 가지거나 논리적으로 같은 값이 존재하는 경우에는 '=' 연산자를 이용하여 EQUI JOIN을 사용한다. 그러나 값이 정확하게 일치하지 않는 경우에는 조인을 사용할 수 없다. 이런 경우 비동등 조인을 시도할 수 있으나 데이터 모델에 따라 비동등조인이 불가능한 경우도 있다. 


예제)

SELECT E.ENAME, E.JOB, E.SAL, S.GRADE

FROM EMP E, SALGRADE S

WHERE E.SAL BETWEEN S.LOSAL AND S.HISAL;





4. 3개 이상 TABLE JOIN

 

예제)

SELECT P.PLAYER_NAME 선수명, P.POSITION 포지션,

T.REGION_NAME 연고지, T.TEAM_NAME 팀명,

S.STADIUM_NAME 구장명

FROM PLAYER P, TEAM T, STADIUM S

WHERE P.TEAM_ID = T.TEAM_ID

AND     T.STADIUM_ID = S.STADIUM_DI

ORDER BY 선수명;





  JOIN이 필요한 기본적인 이유는 정규화에 관련되어있는데, 정규화란 불필요한 데이터의 정합성을 확보하고 이상현상 발생을 피하기 위해, 테이블을 분할하여 생성하는 것이다. 


  테이블을 정규화하여 데이터를 분할하게 되면 과부하 문제도 있고, 규모가 꽤 커지는 문제점을 해결 할 수 있다. 그렇지만 특정 요구조건을 만족하는 데이터들을 분할된 테이블로부터 조회하기 위해서는 테이블 간에 논리적인 연관관계가 필요하고, 그런 관계성을 통해서 다양한 데이터들을 출력할 수 있는 것이다. 그리고, 이런 논리적인 관계를 구체적으로 표현하는 것이 바로 SQL 문장의 JOIN 조건인 것이다.


  관계형 데이터베이스의 큰 장점이면서, SQL 튜닝의 중요 대상이 되는 JOIN을 잘못 기술하게 되면 시스템 자원 부족이나 과다한 응답시간 지연을 발생시키는 중요 원인이 되므로 JOIN 조건은 신중하게 작성해야 한다. 

728x90
반응형

'Computer Science > SQL-D' 카테고리의 다른 글

[SQLD] 22. 집합 연산자 (SET OPERATOR)  (2) 2016.08.31
[SQLD] 21. 표준 조인(STANDARD JOIN)  (0) 2016.08.24
[SQLD] 19. ORDER BY 절  (0) 2016.08.18
[SQLD] 18. GROUP BY, HAVING 절  (0) 2016.08.18
[SQLD] 17. 함수 (Function)  (0) 2016.08.18