JOIN과 데이터 집합
조인을 테이블과 테이블이 아닌 데이터 집합과 데이터 집합 간의 연결로 생각할 필요가 있다. 아래 그림은 A 테이블, B 테이블, C 테이블이 조인하는 과정이다.
위 그림을 설명하면,
•
테이블 A, 테이블 B, 테이블 C를 조인
◦
테이블 A와 테이블 B 조인 → 데이터 집합 AB가 만들어진다.
◦
조인을 통해 만들어진 AB는 물리적인 테이블이 아니므로 데이터 집합으로 해석
◦
데이터 집합 AB와 테이블 C 조인 → 데이터 집합 ABC(최종결과)가 만들어진다.
•
테이블 A, 테이블 B, 테이블 C를 데이터집합 A, 데이터집합 B, 데이터집합 C 로 생각하자.
◦
데이터 집합 A와 데이터 집합 B 조인 → 데이터 집합 AB가 만들어진다.
◦
데이터 집합 AB와 데이터 집합 C 조인 → 데이터 집합 ABC(최종결과)가 만들어진다.
이처럼 SQL 세계에서는 테이블을 데이터 집합으로 생각해도 전혀 이상이 없다. 테이블보다는 데이터 집합이라는 생각을 갖기 바란다.
JOIN은 한 번에 두 개의 데이터 집합만
이제 여러 테이블(데이터 집합)을 조인하기 위해 준비할 차례다. 걱정할 필요 없다. 한 문장의 SQL에서 여러 테이블이 조인 될 때는, 한 순 간에는 두 개의 데이터 집합만 조인에 참여한다고 생각하자. DB 내부적으로 어떻게 처리하는지는 중요하지 않다. 개념적으로 한 번에 두 데이터 집합만 조인할 수 있다고 생각하고 SQL을 작성하자.
아래 그림을 살펴보자. 세 개의 데이터 집합을 조인한다면 그림의 왼쪽과 같이 두 개의 데이터 집합이 조인해 하나의 데이터 집합이 만들어지고, 나머지 하나의 데이터 집합과 조인이 이루어진다. 오른쪽과 같이 세 데이터 집합이 동시에 조인 된다고 생각하지 말자.
위 그림의 왼쪽과 같이 한 순간에는 두 데이터 집합만 연결된다는 개념을 가지고 SQL을 작성하기 바란다.
회원(Member)과 주문(Ord), 그리고 주문상세(OrdDet)를 조인해보자. 조인에 앞서 세 테이블의 구조를 살펴보면 다음과 같다.
테이블 구조를 통해 테이블 간 조인 조건 컬럼을 먼저 정리해보자.
•
Member와 Ord: Member의 PK인 MemberId가 조인 컬럼이다.
•
Ord와 OrdDet: Ord의 PK인 OrdNo가 조인 컬럼이다.
이제 조인 SQL을 작성해보자. 단, 세개 테이블을 조인하는 SQL을 한 번에 완성하려고 하지 말자, 단계적으로 작성하고 실행해 결과를 중간 중간 확인하면서 SQL을 완성하기 바란다.
-- [SQL-7-6-1]
-- 1. Member와 Ord를 먼저 조인하자.
-- NickNm이 Air이면서, 주문일시는 2023년 1월 1일인 주문만 조인할 것이다.
SELECT T1.MemberId ,T1.NickNm ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Member T1
INNER JOIN startdb.Ord T2 ON (T2.MemberId = T1.MemberId)
WHERE T1.NickNm = 'Air'
AND T2.OrdDtm >= STR_TO_DATE('20230101','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20230104','%Y%m%d');
MemberId NickNm OrdNo OrdDtm
-------- ------ ----- -------------------
M0001 Air 67277 2023-01-01 08:00:00
M0001 Air 67286 2023-01-02 08:00:00
M0001 Air 67586 2023-01-03 08:00:00
-- [SQL-7-6-2]
-- 2. 위 데이터집합에 OrdDet를 조인하자.
-- Ord와 OrdDet의 조인 컬럼은 OrdNo다. 그러므로 OrdNo를 사용해 조인을 해야 한다.
-- 조인컬럼으로 Ord 테이블의 OrdNo를 사용하지만,
-- Ord와 OrdDet의 조인이 아니라,
-- (Member와 Ord의 조인 결과 집합)에 OrdDet를 조인한다고 생각하자.
SELECT T1.MemberId ,T1.NickNm ,T2.OrdNo ,T2.OrdDtm ,T3.ItemId ,T3.OrdQty
FROM startdb.Member T1
INNER JOIN startdb.Ord T2 ON (T2.MemberId = T1.MemberId)
INNER JOIN startdb.OrdDet T3 ON (T3.OrdNo = T2.OrdNo)
WHERE T1.NickNm = 'Air'
AND T2.OrdDtm >= STR_TO_DATE('20230101','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20230104','%Y%m%d');
MemberId NickNm OrdNo OrdDtm ItemId OrdQty
-------- ------ ----- ------------------- ------ ------
M0001 Air 67277 2023-01-01 08:00:00 HCHB 1
M0001 Air 67286 2023-01-02 08:00:00 BGLR 1
M0001 Air 67586 2023-01-03 08:00:00 HCHR 1
SQL
복사
세 테이블의 조인 과정을 논리적으로 그려보면 아래와 같다.
위 과정을 말로 풀어보면 다음과 같다.
•
Member에서 NickNm이 Air인 데이터를 가져와 T1 데이터 집합 생성
•
Ord에서 OrdDtm이 2023년 1월 1일~2023년 1월 3일인 데이터를 가져와 T2 데이터 집합 생성
•
T1과 T2 데이터 집합을 조인해 T1T2라는 새로운 데이터집합 생성
•
T1T2 데이터집합과 OrdDet(T3) 데이터집합을 조인
◦
Ord와 OrdDet를 조인하는 것이 아니라,
◦
Member와 Ord의 조인으로 얻은 새로운 데이터 집합과 OrdDet를 조인하는 것이다.
실제 DBMS 내부적으로 이렇게 처리된다고 말할 수는 없다. 하지만 우리가 조인을 작성할 때는 이 처럼 한 번에 두 개씩만 조인된다고 생각하며 조인을 작성하면, 비교적 쉽게 많은 테이블의 조인도 해낼 수 있다. 그리고 이러한 과정이 익숙해지면 많은 테이블을 단숨에 조인하는 것도 전혀 어렵지 않게 될 것이다.
JOIN 순서는 상관 없다.
여러 데이터 집합(테이블)을 조인할 때, 데이터 집합의 조인 순서는 결과에 영향을 주지 않는다. 아래는 네 개의 데이터 집합을 조인하는 예다. 어떤 순서로 조인하든 결과는 ABCD로 같다.
여러 테이블의 조인을 작성할 때, 조인할 테이블들의 순서보다는 조인할 두 데이터 집합 간에 조인 컬럼이 정확한가에 대해 중점을 두기 바란다.
Upper: 7. JOIN