본문 바로가기
데이터 모델과 SQL

[SQL 이해하기] - 8.4. SQL: SELECT IV - JOIN

by 영바이트 2023. 7. 3.

 

데이터를 저장할 때 하나의 테이블에 모든 데이터를 저장하지는 않는다. 가장 큰 단점은 데이터의 중복이 발생하고 같은 데이터가 행에 따라 값이 달라질 수 있는 '일관성 깨짐(inconsistency)'이 발생할 수 있기 때문이다.

 

보통 데이터는 특성별로 여러 테이블에 나뉘어 저장된다. 예를 들어 상품 데이터는 상품 테이블에, 주문 데이터는 주문 테이블에 저장되는 식이다. 이렇게 나뉘어져 저장된 데이터들은 어떤 필요에 의해 연관된다. 예를 들어 상품 데이터와 주문 데이터는 '주문 상품'의 관계로 연결된다. 이와 같이 데이터를 연관짓고 연관된 데이터를 출력하는 것을 JOIN 연산이라고 한다.

 

JOIN  연산은 먼저 JOIN 조건에 따라 equi join과 non-equi join으로 나뉜다. equi join은 데이터들이 동등(=) 조건에 의해 연결되는 것이고, non-equi join은 비교(>, >=, <, <=, BETWEEN) 조건에 의해 연결되는 것이다. Equi, non-equi라는 용어가 자주 사용되기 때문에 알고 있을 필요가 있다.

 

- Equi join의 예

SELECT A.ID, B.PRODUCT_NAME
FROM ORDERS A, PRODUCTS B
WHERE A.PRODUCT_ID = B.PRODUCT_ID

 

- Non-equi join의 예

SELECT A.ID, B.PRODUCT_NAME
FROM ORDERS A, PRODUCTS B
WHERE A.ORDER_DATE BETWEEN '20220601' AND '20220630';

 


 

JOIN 연산의 종류에 대해 살펴보자. JOIN 연산 자체는 앞서 살펴보았던 equi / non-equi join 조건과는 관계가 없다. 각각의 JOIN 연산에서 JOIN 조건으로 equi / non-equi 조건을 모두 사용할 수 있다.

 

- CROSS JOIN

조인의 기본은 CROSS JOIN이다. CROSS JOIN을 다른 이름으로 Cartesian JOIN이라고도 한다. 두 테이블의 행들 사이에 만들어질 수 있는 모든 조합을 생성한다. 예를 들어 테이블 A에 3개의 행이 있고, 테이블 B에 2개의 행이 있다면 CROSS JOIN 결과로 총 3x2 = 6개의 행들이 생성된다.

SELECT ORDERS.ORDER_ID, PRODUCTS.PRODUCT_NAME
FROM ORDERS, PRODUCTS
WHERE ORDERS.PRODUCT_CODE = PRODUCTS.PRODUCT_CODE;

 

- INNER JOIN

INNER JOIN은 조인 조건에 해당하는 행들만 결합한다. 조인 조건을 기준으로 조인 대상이 되는 테이블들의 교집합이라고 보면된다.

SELECT A.ORDER_ID, B.PRODUCT_NAME
FROM ORDERS A INNER JOIN PRODUCTS B
ON A.PRODUCT_CODE = B.PRODUCT_CODE;

 

- OUTER JOIN

OUTER JOIN은 기준 테이블의 데이터는 모두 출력하고 참조 테이블에서 기준 테이블과 매칭되는 데이터가 있으면 함께 출력하는 조인 방식이다. 아래와 같은 순서로 조인 데이터가 출력된다.

① 기준 테이블의 모든 행들을 출력한다.

② 조인 조건에 해당하는 행들을 참조 테이블에서 찾아서 함께 출력한다.

SELECT *
FROM SAMPLE1 A RIGHT OUTER JOIN SAMPLE2 B
ON (A.COL1=B.COL1 AND B.COL2 IS NOT NULL);

→ 일단 OUTER JOIN의 기준 테이블이 되는 SAMPLE2 테이블의 행들이 모두 출력된다. 이 후 조인 조건을 만족하는 행들을 SAMPLE1 테이블에서 찾아서 함께 출력한다.

 

참고로 ORACLE DBMS에서는 RIGHT/LEFT로 기준 테이블을 지정하는 대신 CROSS JOIN을 사용하고 참조 테이블에 (+) 기호를 붙인다.

SELECT *
FROM TABLE_A LEFT OUTER JOIN TABLE_B
ON TABLE_A.ID = TABLE_B.ID;

→ ORACLE

SELECT *
FROM TABLE_A, TABLE_B
WHERE TABLE_A=TABLE_B(+);

 

- FULL OUTER JOIN

FULL OUTER JOIN은 LEFT OUTER JOIN + RIGHT OUTER JOIN - INNER JOIN과 같다. 즉 두 테이블의 조인 조건에 따라 관련되어 있는 모든 행들을  출력한다.

 

- NATURAL JOIN

NATURAL JOIN은 조인 대상 테이블에서 각 컬럼의 값이 같은 행들만 출력한다.

SELECT PRODUCT_NAME, PRODUCT_NAME
FROM ORDERED_PRODUCTS NATURAL JOIN REGISTERED_PRODUCTS;

NATURAL join은 join 대상 테이블의 컬럼들이 모구 같다는 가정 아래 각 컬럼의 값이 모두 같은 행들을 join한다. 따라서 컬럼 이름 앞에 owner 테이블 이름을 표시하지 않는다.

 

만약 ORACLE DBMS를 사용하고 있다면 NATRAL JOIN에서 고려할 컬럼들을 USING 절을 이용해서 지정해 줄 수 있다.

SELECT CAST, GENDER, A.JOB, B.JOB
FROM MOVIE_A A JOIN MOVIE_B B
USING (CAST, GENDER);

단, USING 절에 사용된 컬럼들은 SELECT 절에서 Alias나 테이블 명 접두어를 붙일 수 없다. 이는 아마 해당 컬럼들이 조인 대상 테이블들에 모두 포함되어 있는 공통 컬럼들이기 때문에 헷갈릴 염려가 없기 때문일것이다.

 


 

네 번의 포스팅(8.1 ~ 8.4)에 걸쳐 간단하게 SELECT 구문에 대해 정리해보았다. 다음 포스팅 부터는 쿼리 안에 쿼리가 존재하는 서브 쿼리(sub query)에 대해 정리해보도록 하겠다.

 

* 포스팅을 읽으시다 잘못된 내용을 발견하시면 댓글 부탁드립니다. 살펴보고 수정할께요.

 

 

 

댓글