SQL 기본문법 > JOIN(CROSS, INNER, OUTER, SELF)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


JOIN

하나의 테이블에 원하는 데이터가 모두 있다면 좋겠지만, 두 개의 테이블을 엮어야 원하는 결과가 나오는 경우도 많다. 이때 조인을 쓰면 두개의 테이블을 엮어 원하는 데이터를 추출할 수 있게 한다. 즉 조인이란,

  1. 두 개 이상의 테이블을 연결하여 데이터를 검색하는 방법
  2. 서로 다른 테이블에 저장된 데이터를 함께 가져와 하나의 결과로 표시함
  3. 검색하고 싶은 컬럼이 서로 다른 테이블에 있을 때 사용
  4. 조인을 사용해 여러개의 테이블을 마치 하나의 테이블처럼 사용 가능

조인 방식

  • ANSI SQL
    • FROM 절 안의 두 테이블 사이에 조인 종류(CROSS, INNER, OUTER)에 따라 JOIN 키워드를 넣어줌
    • ON 절에 조인에 대한 조건을 작성하고 나머지 조건은 WHERE 절에 작성
    • CROSS, INNER, OUTER 키워드는 생략 가능
  • Non-ANSI SQL
    • FROM 절에 테이블을 쉼표로 구분해 작성
    • 조인조건, 기타조건을 구분없이 WHERE절에 작성

CROSS JOIN

한 쪽 테이블의 각 행마다 다른 쪽 테이블의 모든 행이 각각 한번씩 매칭되는 조인 (Cartesian Product)

-- 문제1: 사원테이블과 부서테이블을 조인하여 배재용 사원에 대한 정보를 보이시오
-- 이름, 사원테이블의 부서번호, 부서테이블의 부서번호, 부서명
SELECT 사원.이름, 사원.부서번호, 부서.부서번호, 부서.부서명 FROM 사원 JOIN 부서
ON 사원.이름 = '배재용'; 

SELECT 사원.이름, 사원.부서번호, 부서.부서번호, 부서.부서명 FROM 사원,부서
WHERE 사원.이름 = '배재용'; 

INNER JOIN

각 테이블에서 조인 조건에 일치되는 데이터만 가져오는 조인

여러 테이블을 사용할 때 조인조건을 제대로 기술하지 않으면 크로스조인을 한 결과가 나온다

-- 문제1: 이소미 사원의 사원번호, 직위, 부서번호, 부서명을 보이시오
SELECT 사원.이름, 사원.사원번호, 사원.직위, 부서.부서번호, 부서.부서명 FROM 사원 INNER JOIN 부서 
ON 사원.부서번호 = 부서.부서번호  
WHERE 사원.이름 = '이소미';

-- 문제2: 고객 회사들이 주문한 주문건수를 주문건수가 많은 순서대로 보이시오
-- 이때 고객회사의 정보로 고객번호, 담당자명, 고객회사명을 보이시오
SELECT 고객.고객번호, 고객.담당자명, 고객.고객회사명, count(*) 주문건수 FROM 고객 INNER JOIN 주문
ON 고객.고객번호 = 주문.고객번호 
GROUP BY 1
ORDER BY 주문건수 desc;

-- 문제3: 고객별 주문금액 합을 보이되, 주문 금액 합이 많은 순서대로 보이시오
-- 이때 고객회사의 정보로 고객번호, 담당자명, 고객회사명을 보이시오
SELECT 고객.고객번호, 고객.담당자명, 고객.고객회사명, SUM(주문수량*단가) 주문합  
FROM 고객 
INNER JOIN 주문
ON 고객.고객번호 = 주문.고객번호 
INNER JOIN 주문세부
ON 주문.주문번호 = 주문세부.주문번호 
GROUP BY 1
ORDER BY 주문합 desc;

-- 문제4: 고객 테이블에서 담당자가 이은광인 경우 
-- 고객번호, 고객회사명, 담당자명, 마일리지와 마일리지 등급을 보이시오
-- *공통된 컬럼이 없는데, 조인을 하는 예외적인 방법*
SELECT 고객.고객번호, 고객.담당자명, 고객.마일리지, 마일리지, 등급명  
FROM 고객 
INNER JOIN 마일리지등급 M  -- alias 
ON 마일리지등급 BETWEEN 하한마일리지 AND 상한마일리지  -- 이렇게 join에 대한 조건 작성 가능 
WHERE 담당자명 = '이은광';

OUTER JOIN

조건이 맞지 않는 행도 함께 출력할 수 있음. 외부 조인은 두 테이블에서 한쪽에는 데이터가 있고, 한쪽에는 없는 경우 데이터가 있는 쪽의 테이블을 기준으로 데이터를 출력한다. MySQL에서 외부조긴은 ANSI SQL 방식으로만 표현 가능!

이너조인은 양쪽 모두 데이터가 있어야 가능하지만, 외부조인은 한쪽에 데이터가 없더라도 조인이 가능하다. 이때 없는 데이터에 대해서는 모두 null로 채워진다. 따라서 외부조인을 사용할 때 어느쪽 방향으로 조인을 해주는 지 설정하는 것이 중요하다. (데이터가 많은 쪽으로 조인을 해주는 것이 옳다) 이런 것들을 잘하기 위해서는 각 테이블과 컬럼, 각 데이터들간의 관계를 잘 알아야한다.

OUTER는 생략가능

  • LEFT JOIN
    • 왼쪽에 있는 테이블의 결과를 기준으로 오른쪽 테이블 데이터 매칭
    • 매칭되는 데이터가 없는 경우에는 null로 표시
  • RIGHT JOIN
    • 오른쪽에 있는 테이블의 결과를 기준으로 왼쪽 테이블 데이터 매칭
    • 매칭되는 데이터가 없는 경우에는 null로 표시

외부조인을 사용할때 별도의 방향을 정해주지 않으면 FULL OUTER JOIN이 된다는 것을 잊지말자.

-- 문제: 사원번호, 이름, 부서명을 출력하는데, 성별이 여자인 사람을 출력 
SELECT 사원번호, 이름, 부서명 FROM 사원 
LEFT JOIN 부서 ON 사원.부서번호 = 부서.부서번호 
WHERE 성별 = '여';

위 문제의 경우, 사원 테이블에는 부서번호, 사원번호, 이름, 성별 컬럼이 존재하고, 부서 테이블에는 부서번호, 부서명이 존재했다. 따라서 부서 테이블을 사원테이블에 조인시키고 각 테이블은 공통된 부서번호로 연결시켰다. 이때 아래 이미지를 보면 부서명이 존재하지 않는 사원에 대해서도 null이 들어감으로써 테이블이 제대로 만들어진 것을 볼 수 있다. 이렇듯 데이터가 존재하지 않아도 조인을 하기 위해서 외부조인을 사용하는 것을 알 수 있다.

즉, 부서명이 없는 정수진이라는 사람의 데이터도 얻기 위해서는 외부조인을 사용해야한다.

-- 문제: 부서명과 해당 부서의 소속사원 정보를 보이시오.
-- 이때 사원이 한명도 존재하지 않는 부서명이 있다면 그 부서명도 보이시오.
SELECT * FROM 부서 LEFT JOIN 사원  
ON 사원.부서번호 = 부서.부서번호;

없는 사원에 대한 데이터까지 보고싶은 것이기 때문에 부서에 대해 사원을 외부 조인 해줘야 한다.

그렇다면 사원이 없는 부서만 뽑아내려면 어떻게 해야할까?

SELECT * FROM 사원 LEFT JOIN 부서  
ON 사원.부서번호 = 부서.부서번호
WHERE 부서명 IS NULL;

SELECT * FROM 부서 LEFT JOIN 사원  
ON 사원.부서번호 = 부서.부서번호
WHERE 이름 IS NULL;

이렇듯 원하는 기준이 무엇이냐에 따라 어느쪽으로 조인을 할지 잘 선택하는 것이 중요하다. 그리고 그 방향을 설정하고 난 다음에는 데이터를 어떻게 뽑아올 지 잘 고민해봐야할 것 같다. 별개로 위에서 또 중요한 점은 is null을 사용했다는 것이다. 외부조인에 is null을 사용함으로서 겹치는 영역이 없는 한쪽 테이블의 값을 가져올 수도 있다.

이 이미지를 잊지말자.

SELF JOIN

동일한 테이블 내에서 한 컬럼이 다른 컬럼을 참조하는 조인

동일한 테이블명이 조인조건에 두번 나타나는 것이 특징으로, 이때 테이블명을 다른 별명으로 지정해 다른 테이블인 것처럼 사용한다. 이때 컬럼명도 동일하기 때문에 컬럼명 또한 별명을 지어줌으로써 컬럼의 소속 또한 구분해주어야 한다.

-- 문제1: 사원번호, 사원의 이름, 상사의 사원번호, 상사의 이름을 보이시오
SELECT 사원.사원번호, 사원.이름, 상사.사원번호 as 상사번호, 상사.이름 as 상사이름 FROM 사원, 사원 AS 상사
WHERE 상사.사원번호 = 사원.상사번호; 

-- 문제2: 사원이름, 직위, 상사이름을 상사이름 순으로 정렬하여 나타내시오.
-- 이때 상사가 없는 사원의 이름도 함께 보이시오