CS/DB

[혼공SQL] 두 테이블을 묶는 JOIN

F12:) 2024. 1. 17. 00:18

 

  JOIN

두 개의 테이블을 묶어서 하나의 결과를 내는 것을 말합니다. 두 개뿐만 아니라 3개, 4개도 가능하지만 2개가 통상적으로 사용됩니다.

 

예를 들어 회원 테이블에는 회원 이름과 연락처, 주소 정보가 있고 구매 테이블에는 회원이 구매한 물건의 정보가 있다고 해봅시다. 물건 배송을 위해서는 각 물건에 따른 회원의 주소 정보가 필요합니다. 따라서 이러한 경우에 두 테이블을 묶는 JOIN이 필요하게 됩니다. 

 

JOIN에는 내부 조인, 외부 조인, 상호 조인, 자체 조인이 있으며 이에 대해서 다뤄보겠습니다.

 

 

  내부 조인

내부 조인은 두 테이블 사이에 어느 열에 공통된 데이터가 있을 때 사용할 수 있습니다. 또한 내부 조인을 위해서는 두 테이블이 일대다 관계로 연결되어 있어야합니다.

 

내부 조인의 형식은 아래와 같습니다.

SELECT <열 목록>
	FROM <첫 번째 테이블>
    	INNER JOIN <두 번째 테이블>
        ON <조인될 조건>
    [WHERE 검색 조건];

INNER JOIN을 JOIN이라고 써도 동일하게 작용합니다.

 

위 형식을 따라 작성한 SQL문을 확인해봅시다. 해당 SQL문은 member 테이블에 해당하는 member가 주문한 기록인 buy 테이블을 합쳐서 조회하는 것입니다.

SELECT buy.mem_id, member.mem_name, buy.prod_name,member.addr,
                   CONCAT(member.phone1, member.phone2) '연락처'
    FROM buy
    	INNER JOIN member
        ON buy.mem_id = member.mem_id
    WHERE buy.mem_id = 'GRL';

 

이 SQL은 아래와 같은 순서로 동작합니다.

  1. buy 테이블에서 mem_id가 'GRL'인 데이터를 추출합니다.
  2. member 테이블에서 mem_id가 'GRL'인 데이터를 찾습니다.
  3. 그렇게 찾은 두 데이터를 결합(JOIN)합니다.

 

주의해야할 점은 두 테이블에 같은 이름의 열이 존재할 수 있다는 것입니다. 이 때는 두 개의 테이블의 열 이름의 혼동을 막기 위해서 꼭 열 이름의 앞에 테이블 명을 명시하는 것이 좋습니다.

 

그러나 테이블의 이름이 긴 경우에는 모든 열 이름에 테이블 이름을 명시하는 것이 번거롭습니다. 이 때는 별칭(alias)을 사용합니다. 테이블의 이름에 별칭을 주어, 간단하게 줄일 수 있습니다.

SELECT B.mem_id, M.mem_name, B.prod_name, M.addr,
                   CONCAT(M.phone1, M.phone2) '연락처'
    FROM buy B
    	INNER JOIN member M
        ON B.mem_id = M.mem_id
    WHERE B.mem_id = 'GRL';

 

 

또한 중복된 결과를 무시하기 위한 DISTINCT도 사용할 수 있습니다.

SELECT DISTINCT M.mem_id, M.mem_name, M.addr
	FROM buy B
    	INNER JOIN member M
        ON B.mem_id = M.mem_id
    ORDER BY M.mem_id;

 

이렇게 되면 mem_id의 값이 중복되지 않습니다.

 

 

  외부 조인

내부조인은 양쪽 테이블에 모두 값이 있어야 존재했습니다. 하지만 외부 조인은 양 쪽 테이블 중 하나의 테이블에만 데이터가 있어도 가능한 JOIN입니다.

 

형식은 아래와 같습니다.

SELECT <열 목록>
	FROM <첫 번째 테이블(LEFT 테이블)>
		<LEFT | RIGHT | FULL> OUTER JOIN <두번 째 테이블(RIGHT 테이블)>
		ON <조인될 조건>
	[WHERE 검색 조건];

 

 

바로 사용되는 예제를 확인해봅시다. 앞선 내부 조인에서는 member 중에서 구매한 이력이 있는 데이터를 조회하는 SQL 문이었다면, 외부 조인은 member 중에서 구매 이력이 없는 member도 함께 조회되도록 합니다.

SELECT M.mem_id, M.mem_name, B.prod_name, M.addr
	FROM member M
		LEFT OUTER JOIN buy B
		ON M.mem_id = B.mem_id
	ORDER BY M.mem_id;

LEFT OUTER JOIN을 줄여서 LEFT JOIN이라고만 써도 됨.

 

LEFT OUTER JOIN에서 LEFT는 '왼쪽 테이블의 내용은 모두 출력되어야 한다' 정도로 이해하면 됩니다.

 

 

조금 더 나아가 한 번도 구매한 적이 없는 회원들만 조회해봅시다.

SELECT DISTINCT M.mem_id, B.prod_name, M.mem_name, M.addr
	FROM member M
		LEFT OUTER JOIN buy B
		ON M.mem_id = B.mem_id
	WHERE B.prod_name IS NULL
	ORDER BY M.mem_id;

IS NULL을 사용합니다. WHERE에서는 JOIN 후의 결과를 확인합니다. JOIN 후에는 구매 이력이 없는 member에는 buy 테이블 부분이 모두 NULL일 것을 이용한 것입니다.

 

이 외에도 RIGHT, FULL이 있습니다. FULL OUTER JOIN은 왼쪽이든 오른쪽이든 한 쪽에 들어있으면 출력하는 방법이지만 잘 사용하지 않습니다.

 

 

  기타 조인

상호 조인(cross join)

하나의 행과 다른 테이블의 전체 행을 JOIN하는 것을 의미합니다. 아래처럼 사용할 수 있습니다.

SELECT * FROM buy
	CORSS JOIN member;

 

그래서 상호 조인의 결과로 나온 테이블의 행의 개수는 항상 두 테이블의 행의 개수를 곱한 것과 같습니다. 

사실 상호 조인무의미한 데이터를 대량으로 만들어 테스트용 테이블을 만들 때 사용합니다.

 

 

자체 조인

자기 자신과 조인하는 것을 의미합니다. 단지 LEFT와 RIGHT 테이블에 별칭만 다르게하여 같은 테이블을 넣어주면 됩니다.

 

예를 들어봅시다. 아래와 같은 회사 조직도가 있다고 해봅시다.

 

또한 아래와 같은 데이터베이스가 있어, 해당 테이블에서 직원 중 경리부장의 직속 상관인 관리이사의 사내 연락처를 알고싶다고 해봅시다.

그렇다면 EMP 열과 MANAGER 열을 조인해야합니다.

emp_table

 

그렇다면 아래와 같이 SQL문을 구성할 수 있습니다.

SELECT A.emp, B.emp, B.phone
	FROM emp_table A
		INNER JOIN emp_table B
		ON A.manager = B.emp
	WHERE A.emp = '경리부장';