OUTER JOIN 이해하기
아우터 조인(OUTER JOIN)은 이너 조인(INNER JOIN)과 마찬가지로 데이터와 데이터를 결합하는 조인의 한 종류다. 이너 조인은 조인 조건을 만족하는 데이터만 결합해 조인 결과로 내보내는 반면에 아우터 조인은 조인 조건에 만족하지 않는 데이터도 결과에 포함하는 특징이 있다.
아우터 조인의 특징을 정리해보면 다음과 같다.
•
기준 집합(기준 테이블)은 조인 조건을 만족하지 않아도 무조건 결과에 출력 된다.
◦
단, 필터 조건은 만족해야 한다.
•
데이터 분석을 위해 자주 사용한다.
◦
예를 들어, 주문이 없는 매장 정보도 출력하기 위해 사용할 수 있다.
▪
주문과 매장을 이너조인하면, 주문이 없는 매장은 결과에 나올 수 없다.
▪
아우터 조인을 사용하면 주문이 없는 매장도 결과에 나오게 할 수 있다.
다음 데이터를 조인하지 말고 각각 조회해보자.
•
Shop에서 ShopId가 S070과 S071인 데이터
•
Ord에서 ShopId가 S070이거나 S071이면서 OrdDtm이 2022년 11월 21일인 데이터
-- [SQL-7-9-1] S070, S071 Shop 정보
SELECT T1.ShopId ,T1.ShopNm, T1.ShopSt
FROM startdb.Shop T1
WHERE T1.ShopId IN ('S070','S071');
ShopId ShopNm ShopSt
------ ------------ ------
S070 San Jose-4th OPEN
S071 Austin-4th OPEN
-- [SQL-7-9-2] S070, S071 Ord 정보(S070 없음)
SELECT T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Ord T2
WHERE T2.ShopId IN ('S070','S071')
AND T2.OrdDtm >= STR_TO_DATE('20221121','%Y%m%d')
AND T2.OrdDtm <= STR_TO_DATE('20221122','%Y%m%d')
ORDER BY T2.ShopId ,T2.OrdNo;
ShopId OrdNo OrdDtm
------ ----- -------------------
S071 48166 2022-11-21 14:00:00
S071 48196 2022-11-21 14:00:00
S071 48228 2022-11-21 14:00:00
SQL
복사
결과를 보면 Shop 테이블에는 두 매장(S070, S071)의 데이터가 존재하지만, Ord 테이블에는 S071 매장의 주문만 존재한다. 우선 두 데이터 집합을 지금까지 해온 것처럼 이너 조인으로 처리해보자. 당연히 조인 조건에 만족하지 못하는 S070 매장 정보는 사라지게 된다.
-- [SQL-7-9-3] Shop과 Ord를 INNER JOIN
SELECT T1.ShopId ,T1.ShopNm, T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Shop T1
INNER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId)
WHERE T1.ShopId IN ('S070','S071')
AND T2.ShopId IN ('S070','S071')
AND T2.OrdDtm >= STR_TO_DATE('20221121','%Y%m%d')
AND T2.OrdDtm <= STR_TO_DATE('20221122','%Y%m%d')
ORDER BY T1.ShopId;
ShopId ShopNm ShopId OrdNo OrdDtm
------ ---------- ------ ----- -------------------
S071 Austin-4th S071 48166 2022-11-21 14:00:00
S071 Austin-4th S071 48196 2022-11-21 14:00:00
S071 Austin-4th S071 48228 2022-11-21 14:00:00
SQL
복사
이번에는 아우터 조인으로 변경해서 실행해보자. ‘INNER JOIN’ 이라고 작성했던 부분을 ‘LEFT OUTER JOIN’으로 변경하고, Ord 테이블에 대한 필터 조건(ShopId와 OrdDtm에 대한 조건)을 WHERE 절이 아닌 ON 절로 옮겨 적으면 된다.다음과 같다.
-- [SQL-7-9-4] Shop과 Ord를 OUTER JOIN
SELECT T1.ShopId ,T1.ShopNm
,T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.ShopId IN ('S070','S071') -- > 조인 조건과 같은 조건이므로 생략 가능
AND T2.OrdDtm >= STR_TO_DATE('20221121','%Y%m%d')
AND T2.OrdDtm <= STR_TO_DATE('20221122','%Y%m%d'))
WHERE T1.ShopId IN ('S070','S071')
ORDER BY T1.ShopId;
ShopId ShopNm ShopId OrdNo OrdDtm
------ ------------ ------ ----- -------------------
S070 San Jose-4th NULL NULL NULL
S071 Austin-4th S071 48228 2022-11-21 14:00:00
S071 Austin-4th S071 48196 2022-11-21 14:00:00
S071 Austin-4th S071 48166 2022-11-21 14:00:00
SQL
복사
이너 조인에서 사라졌던 S070 매장의 데이터가 아우터 조인 결과에는 포함되어 있는 것을 알 수 있다. S070 매장에 대한 Shop 테이블의 정보(ShopId, ShopNm)는 결과에 포함되어 있고, Ord 테이블의 정보(ShopId, OrdNo, OrdDtm)는 NULL로 채워져 있다.
기준집합과 참조집합
아우터 조인을 제대로 다루기 위해서는 조인에 참가하는 테이블을 기준집합과 참조집합으로 나누어서 구분할 필요가 있다. 기준집합은 조인의 기준이 되는 집합으로서 조인 조건에 만족하지 않아도 조인 결과에 포함되는 집합이다. 단, 필터 조건은 만족해야 한다. 당연히 기준집합이 아닌 쪽은 참조집합이 된다. 기준집합과 참조집합에 대해서 다음과 같이 정리해볼 수 있다.
•
기준집합과 참조집합: 아우터 조인을 수행하는 두 데이터 집합은 반드시 기준과 참조로 나뉜다.
•
기준집합(기준 테이블): 조인 조건에 만족하지 않은 데이터도 결과에 참여한다.
◦
단, 필터 조건은 만족해야 한다.
◦
조인 조건에 만족하지 못했다는 것은 기준집합에는 데이터가 존재하지만, 참조집합에 결합할 대상 데이터가 없다는 뜻이다.
▪
이 경우(조인 조건을 만족 못함), 기준집합은 데이터가 있지만 참조쪽 데이터가 없기 때문에, 참조쪽 컬럼의 값들은 NULL로 채워서 보여준다.
•
참조집합(참조 테이블): 조인 조건에 만족하지 않은 데이터는 조인 결과에 참여하지 못한다.
아우터 조인은 LEFT OUTER JOIN, RIGHT OUTER JOIN 그리고 FULL OUTER JOIN이 있다. MySQL은 FULL OUTER JOIN을 지원하지 않는다.(8.0.35 기준) 그리고 FULL OUTER JOIN을 실제 사용해야 할 경우도 잘 없다. 개인적으로 FULL OUTER JOIN 구문을 이해할 필요는 없다고 생각한다. LEFT OUTER JOIN과 RIGHT OUTER JOIN에 대해 정리해보면 다음과 같다.
•
LEFT OUTER JOIN
◦
해당 문장을 중심으로 왼쪽의 테이블이 기준집합이다. 반대편은 참조집합이 된다.
◦
LEFT JOIN으로 줄여서 사용할 수도 있다.
•
RIGHT OUTER JOIN
◦
해당 문장을 중심으로 오른쪽의 테이블이 기준집합이다. 반대편은 참조집합이 된다.
◦
RIGHT JOIN으로 줄여서 사용할 수도 있다.
•
OUTER JOIN을 사용해야 한다면, 가능하면 LEFT OUTER JOIN만 사용하자.
•
실제 RIGHT OUTER JOIN을 사용하는 경우는 많지 않다.
•
한 문장의 SQL에서 LEFT OUTER JOIN과 RIGHT OUTER JOIN을 섞어 사용하지 않는다.
◦
이처럼 사용하면 SQL을 이해하기 어려워지며, 이처럼 작성하는 경우도 잘 없다.
LEFT OUTER JOIN으로 데이터가 결합되는 과정을 살펴보면 다음과 같다. 그림과 같이 살펴보기 바란다.
•
Shop에는 세 건의 데이터, Ord에는 네 건의 데이터만 있다고 가정
•
Shop T1 LEFT OUTER JOIN Ord T2 이므로 아우터 조인이 수행된다.
◦
LEFT쪽인, Shop이 기준집합, Ord가 참조집합이다.
•
S001, S002 매장은 조인 조건에 만족하므로 데이터가 결합되어 결과에 출력된다.
•
S003 매장은 Shop에는 있지만 Ord에는 없다.
◦
LEFT OUTER JOIN이므로 기준집합인 Shop의 정보는 그대로 조인 결과에 포함된다.
▪
참조집합인 Ord에 대한 정보는 NULL 로 채워져 결과에 포함된다.
이번에는 RIGHT OUTER JOIN으로 데이터가 결합되는 과정을 살펴보자.
•
Shop에는 세 건의 데이터, Ord에는 네 건의 데이터만 있다고 가정한다.
•
Shop T1 RIGHT OUTER JOIN Ord T2 이므로 아우터 조인이 수행된다.
◦
오른쪽에 있는 Ord가 기준집합, Shop이 참조집합이 된다.
•
S001, S002 매장은 조인 조건에 만족하므로 데이터가 결합되어 결과에 출력된다.
•
S004 매장은 Ord에는 있지만 Shop에는 없다.
◦
기준집합인 Ord의 정보는 그대로 조인 결과에 포함된다.
▪
참조집합은 Shop에 대한 정보는 NULL 로 채워져 결과에 나온다.
아우터 조인을 사용할때는 항상 기준집합이 어느쪽인가를 잘 확인하기 바란다. 또는 어느 테이블을 기준집합으로 해야 하는지 잘 고민하기 바란다.
간단한 연습을 해보자. (SQL-1)과 (SQL-2)의 결과를 살펴보고 (SQL-3)에 대한 질문에 답해보자. (SQL-3)은 (SQL-1)과 (SQL-2)를 아우터 조인한 SQL이다.
-- [SQL-7-9-5]
-- (SQL-1)
SELECT T1.ShopId ,T1.ShopNm
FROM startdb.Shop T1
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId ShopNm
------ ---------------
S001 New York-1st
S002 Los Angeles-1st
S003 Chicago-1st
-- (SQL-2)
SELECT T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Ord T2
WHERE T2.ShopId IN ('S001','S002','S003')
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220123','%Y%m%d')
ORDER BY T2.ShopId;
ShopId OrdNo OrdDtm
------ ----- -------------------
S003 25722 2022-01-20 08:00:00
S003 25725 2022-01-21 08:00:00
S003 25728 2022-01-22 08:00:00
-- (SQL-3)
SELECT T1.ShopId ,T1.ShopNm, T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220123','%Y%m%d'))
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
-- 위 SQL의 기준 집합을 말하시오.
-- 위 SQL의 참조 집합을 말하시오.
-- S001인 데이터는 몇 건이 나오는가?
-- S002인 데이터는 몇 건이 나오는가?
-- S003인 데이터는 몇 건이 나오는가?
SQL
복사
또 다른 간단한 연습이다. 아래 그림에서 괄호 부분을 채워보기 바란다. 왼쪽의 두 개 테이블이 어떤 방식으로 조인하면 오른쪽과 같은 결과가 나왔는지 적으면 된다.
OUTER JOIN의 FILTER 조건 위치
아우터 조인은 필터 조건의 위치에 따라 결과가 달라진다. 아래 규칙을 지켜 필터 조건을 작성해야 한다.
•
아우터 조인에서 참조집합의 필터 조건은 ON 절에 주는 것이 일반적이다.
•
아우터 조인에서 기준집합의 필터 조건은 WHERE 절에 주는 것이 일반적이다.
다음 두 SQL을 비교해보자. 둘 다 Shop이 기준집합이고 Ord가 참조집합인 OUTER JOIN이다. (SQL-1)은 참조 집합(Ord)의 필터 조건을 ON 절에 사용했고, (SQL-2)는 참조 집합(Ord)의 필터 조건을 WHERE 절에 사용했다.
-- [SQL-7-9-6] 참조집합의 필터 조건을 ON 절에 사용
-- 조인 전에 필터 조건이 처리된다.
SELECT T1.ShopId ,T1.ShopNm, T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220123','%Y%m%d'))
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId ShopNm ShopId OrdNo OrdDtm
------ --------------- ------ ----- -------------------
S001 New York-1st NULL NULL NULL
S002 Los Angeles-1st NULL NULL NULL
S003 Chicago-1st S003 25728 2022-01-22 08:00:00
S003 Chicago-1st S003 25725 2022-01-21 08:00:00
S003 Chicago-1st S003 25722 2022-01-20 08:00:00
-- [SQL-7-9-7] 참조집합의 필터 조건을 WHERE 절에 사용
-- 조인 후에 필터 조건이 처리된다. INNER JOIN과 결과가 같다.
SELECT T1.ShopId ,T1.ShopNm, T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId)
WHERE T1.ShopId IN ('S001','S002','S003')
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220123','%Y%m%d')
ORDER BY T1.ShopId;
ShopId ShopNm ShopId OrdNo OrdDtm
------ ----------- ------ ----- -------------------
S003 Chicago-1st S003 25722 2022-01-20 08:00:00
S003 Chicago-1st S003 25725 2022-01-21 08:00:00
S003 Chicago-1st S003 25728 2022-01-22 08:00:00
SQL
복사
참조집합의 필터 조건의 위치에 따라 결과가 다른 것을 알 수 있다. 참조집합의 필터 조건을 WHERE 절에 사용하면 이너 조인과 같은 결과가 된다. 이러한 결과를 원한다면 이너 조인을 사용하면 된다. 굳이 아우터 조인을 할 이유가 없다.
OUTER JOIN과 OUTER JOIN
OUTER JOIN 후에 또 다른 테이블과 OUTER JOIN을 할 때 조인에 사용할 컬럼에 주의해야 한다. 어느 컬럼과 조인을 하느냐에 따라 결과가 달라진다. 아래는 Shop과 Ord를 아우터 조인한 SQL이다.
-- [SQL-7-9-8] Shop과 Ord 아우터 조인
SELECT T1.ShopId ShopId_T1 ,T1.ShopNm
,T2.ShopId ShopId_T2 ,T2.OrdNo
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220121','%Y%m%d'))
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId_T1 ShopNm ShopId_T2 OrdNo
--------- --------------- --------- -----
S001 New York-1st NULL NULL
S002 Los Angeles-1st NULL NULL
S003 Chicago-1st S003 25722
SQL
복사
위와 같은 데이터 집합에 Shop 테이블을 한 번 더 아우터 조인으로 추가해보자. 다음과 같다.
-- [SQL-7-9-9] Shop과 Ord 아우터 조인에 Shop을 다시 아우터 조인
-- 마지막 조인에서 Ord쪽의 ShopId를 조인 조건으로 사용
SELECT T1.ShopId ShopId_T1 ,T1.ShopNm
,T2.ShopId ShopId_T2 ,T2.OrdNo
,T3.ShopId ShopId_T3
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220121','%Y%m%d'))
LEFT OUTER JOIN startdb.Shop T3
ON (T3.ShopId = T2.ShopId) -- > 아우터 조인 추가, T2.ShopId를 조건으로 사용
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId_T1 ShopNm ShopId_T2 OrdNo ShopId_T3
--------- --------------- --------- ----- ---------
S001 New York-1st NULL NULL NULL
S002 Los Angeles-1st NULL NULL NULL
S003 Chicago-1st S003 25722 S003
SQL
복사
Shop(T3)을 조인할 때 아우터 조인을 사용했고, T2 테이블의 ShopId를 조인 조건으로 받아서 처리했다. 첫 번째 두 번째 레코드의 T2쪽 ShopId는 NULL로 채워져 있다. NULL 값이 Shop(T3)의 조인 조건으로 사용되었고 Shop(T3)에는 ShopId가 NULL인 데이터가 없으므로 NULL로서 조인 결과에 참여하게 된다.
이번에는 다음과 같이 Shop(T3)와의 아우터 조인에 T1.ShopId를 조인 조건으로 사용해 보자. T3의 ShopId 값이 채워져 있는 것을 알 수 있다.
-- [SQL-7-9-10] Shop과 Ord 아우터 조인에 Shop을 다시 아우터 조인
-- 마지막 조인에서 Shop쪽의 ShopId를 조인 조건으로 사용
SELECT T1.ShopId ShopId_T1 ,T1.ShopNm
,T2.ShopId ShopId_T2 ,T2.OrdNo
,T3.ShopId ShopId_T3
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220121','%Y%m%d'))
LEFT OUTER JOIN startdb.Shop T3
ON (T3.ShopId = T1.ShopId) -- > 아우터 조인 추가, T1.ShopId를 조건으로 사용
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId_T1 ShopNm ShopId_T2 OrdNo ShopId_T3
--------- --------------- --------- ----- ---------
S001 New York-1st NULL NULL S001
S002 Los Angeles-1st NULL NULL S002
S003 Chicago-1st S003 25722 S003
SQL
복사
아우터 조인이 연속해서 사용될 때 어느 컬럼의 조인 조건을 받는지에 따라 결과가 달라지게 된다. 원하는 결과가 무엇인지 잘 생각해보고 그에 맞게 아우터 조인의 조건을 사용해야 한다.
OUTER JOIN과 INNER JOIN
아우터 조인의 결과 집합에서 참조 집합쪽의 일부 데이터는 NULL이다. 그러므로 이미 조인된 참조집합쪽에 추가로 조인이 발생한다면 이너 조인을 사용해야 할지, 아우터 조인을 사용해야 할지 고민이 필요하다. 아래는 Shop과 Ord를 아우터 조인한 예다.
-- [SQL-7-9-11] Shop과 Ord를 아우터 조인
SELECT T1.ShopId ,T2.ShopId ,T2.OrdNo ,T2.OrdDtm
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220121','%Y%m%d'))
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId ShopId OrdNo OrdDtm
------ ------ ----- -------------------
S001 NULL NULL NULL
S002 NULL NULL NULL
S003 S003 25722 2022-01-20 08:00:00
SQL
복사
위 결과에 OrdDet(주문상세)를 추가로 조인해보자. Ord와 OrdDet는 OrdNo 컬럼으로 조인된다. 아래와 같이 OrdDet를 아우터 조인으로 추가해보자.
-- [SQL-7-9-12] Shop과 Ord 아우터 조인에 OrdDet를 아우터 조인
SELECT T1.ShopId ,T2.ShopId ,T2.OrdNo
,T3.OrdNo ,T3.OrdDetNo ,T3.ItemId
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220121','%Y%m%d'))
LEFT OUTER JOIN startdb.OrdDet T3
ON (T3.OrdNo = T2.OrdNo)
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId ShopId OrdNo OrdNo OrdDetNo ItemId
------ ------ ----- ----- -------- ------
S001 NULL NULL NULL NULL NULL
S002 NULL NULL NULL NULL NULL
S003 S003 25722 25722 1 CLB
S003 S003 25722 25722 2 HCHR
SQL
복사
OrdNo가 NULL이었던 데이터에 OrdDet 데이터가 NULL로서 추가된 것을 알 수 있다. 이번에는 OrdDet에 대한 조인을 아래와 같이 INNER JOIN으로 변경해 보자. S001 매장과 S002 매장이 사라진 것을 알 수 있다. 이처럼 아우터 조인의 참조집합에 조인이 추가될 때는 또 다시 아우터 조인을 사용해야 기존에 만들어진 데이터가 보존될 수 있다.
-- [SQL-7-9-13] Shop과 Ord 아우터 조인에 OrdDet를 이너 조인
SELECT T1.ShopId ,T2.ShopId ,T2.OrdNo
,T3.OrdNo ,T3.OrdDetNo ,T3.ItemId
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220121','%Y%m%d'))
INNER JOIN startdb.OrdDet T3
ON (T3.OrdNo = T2.OrdNo)
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
ShopId ShopId OrdNo OrdNo OrdDetNo ItemId
------ ------ ----- ----- -------- ------
S003 S003 25722 25722 1 CLB
S003 S003 25722 25722 2 HCHR
SQL
복사
ANSI VS. ORACLE
지금까지 ANSI 기준으로 아우터 조인을 살펴봤다. 오라클의 경우 ANSI와 다르게 WHERE 절에 조인 조건을 기술한다. 이때 아우터 조인에는 (+) 기호를 사용해 기준집합과 참조집합을 구분해야 한다.
•
오라클은 WHERE 절에서 (+)가 붙은 쪽이 참조 집합이다.
•
참조 집합쪽의 조인 조건 컬럼과 필터 조건 컬럼 뒤에 모두 (+)를 추가해야 한다.
•
(+)가 있는 쪽은 NULL로서 데이터가 달라 붙는 집합이라고 기억하는 것도 방법이다.
-- [SQL-7-9-14] ANSI 기준 아우터 조인
SELECT T1.ShopId ,T1.ShopNm, T2.ShopId ,T2.OrdNo ,T2.OrdAmt
FROM startdb.Shop T1
LEFT OUTER JOIN startdb.Ord T2
ON (T2.ShopId = T1.ShopId
AND T2.OrdDtm >= STR_TO_DATE('20220120','%Y%m%d')
AND T2.OrdDtm < STR_TO_DATE('20220123','%Y%m%d'))
WHERE T1.ShopId IN ('S001','S002','S003')
ORDER BY T1.ShopId;
-- [SQL-7-9-15] 오라클 기준 아우터 조인, MySQL에서는 실행 불가
SELECT T1.ShopId ,T1.ShopNm, T2.ShopId ,T2.OrdNo ,T2.OrdAmt
FROM startdb.Shop T1
,startdb.Ord T2
WHERE T1.ShopId IN ('S001','S002','S003')
AND T2.ShopId(+) = T1.ShopId
AND T2.OrdDtm(+) >= TO_DATE('20220120','YYYYMMDD')
AND T2.OrdDtm(+) < TO_DATE('20220123','YYYYMMDD')
ORDER BY T1.ShopId;
ShopId ShopNm ShopId OrdNo OrdAmt
------ --------------- ------ ----- --------
S001 New York-1st NULL NULL NULL
S002 Los Angeles-1st NULL NULL NULL
S003 Chicago-1st S003 25728 4000.000
S003 Chicago-1st S003 25725 4000.000
S003 Chicago-1st S003 25722 8500.000
SQL
복사
BOOSTER QUIZ
BOOSTER QUIZ ERD
BOOSTER QUIZ 7-9-1
닉네임이 Air, Apple, Cloud인 회원의 2020년 1월 1일부터 2020년 1월 3일까지의 주문 데이터를 조회해주세요. 주문이 없는 회원도 보여주세요.
•
대상 테이블: 회원(Member)와 주문(Ord)
•
조회 조건
◦
NickNm이 Air, Apple, Cloud인 회원들의
◦
OrdDtm이 2020년 1월 1일부터 2020년 1월 3일까지의 데이터.
•
조회 컬럼: MemberId, NickNm, OrdNo, OrdDtm, OrdAmt
•
추가 조건: 주문이 없는 회원도 조회되도록 처리하시오.
MemberId NickNm OrdNo OrdDtm OrdAmt
-------- ------ ----- ------------------- --------
M0001 Air 1212 2020-01-01 08:00:00 8500.000
M0001 Air 1214 2020-01-02 08:00:00 7000.000
M0001 Air 1234 2020-01-03 08:00:00 2500.000
M0002 Apple NULL NULL NULL
M0003 Cloud NULL NULL NULL
SQL
복사
BOOSTER QUIZ 7-9-2
플래티넘 등급이면서 2020년 1월 4일에 가입한 회원의 2020년 2월의 주문과 주문상세 데이터를 보여주세요. 주문이 없는 데이터도 출력해주세요. 주문상세의 주문한 상품명도 꼭 같이 보여주세요.
•
대상 테이블: 회원(Member), 주문(Ord), 주문상세(OrdDet), 상품(Item)
•
조회 조건
◦
JoinDtm이 2020년 1월 4일이면서 MemberGd가 PLAT인 회원
◦
OrdDtm이 2020년 2월인 주문 데이터
•
조회 컬럼: MemberId ,NickNm ,JoinDtm ,MemberGd ,OrdNo ,OrdDtm ,OrdDetNo ,ItemId, ItemNm, OrdQty
•
추가 조건
◦
주문이 없는 회원도 조회되도록 처리하시오.
◦
Item과 조인해서 ItemNm도 보여주시오.
•
정렬 기준
◦
MemberId로 오름차순한후에 OrdNo, OrdDetNo로 오름차순하시오.
MemberId NickNm JoinDtm MemberGd OrdNo OrdDtm OrdDetNo ItemId ItemNm OrdQty
-------- ------- ------------------- -------- ----- ------------------- -------- ------ ------------------- ------
M1051 Air21 2020-01-04 00:00:00 PLAT NULL NULL NULL NULL NULL NULL
M1212 Fire24 2020-01-04 00:00:00 PLAT NULL NULL NULL NULL NULL NULL
M1213 Flame24 2020-01-04 00:00:00 PLAT NULL NULL NULL NULL NULL NULL
M1238 Sky24 2020-01-04 00:00:00 PLAT NULL NULL NULL NULL NULL NULL
M1252 Apple25 2020-01-04 00:00:00 PLAT 1513 2020-02-02 11:00:00 1 AMR Americano(R) 1
M1308 Dark26 2020-01-04 00:00:00 PLAT 1547 2020-02-04 14:00:00 1 HCHB Hot Chocolate(B) 1
M1308 Dark26 2020-01-04 00:00:00 PLAT 1621 2020-02-06 14:00:00 1 ICLB Iced Cafe Latte(B) 1
M1308 Dark26 2020-01-04 00:00:00 PLAT 1621 2020-02-06 14:00:00 2 BMFR Blueberry Muffin(R) 1
M1308 Dark26 2020-01-04 00:00:00 PLAT 1645 2020-02-08 14:00:00 1 HCHB Hot Chocolate(B) 1
M1308 Dark26 2020-01-04 00:00:00 PLAT 1645 2020-02-08 14:00:00 2 BGLR Bagel(R) 1
M1308 Dark26 2020-01-04 00:00:00 PLAT 1725 2020-02-13 14:00:00 1 BMFR Blueberry Muffin(R) 1
M1308 Dark26 2020-01-04 00:00:00 PLAT 1761 2020-02-21 14:00:00 1 ICLB Iced Cafe Latte(B) 1
M1322 Light26 2020-01-04 00:00:00 PLAT NULL NULL NULL NULL NULL NULL
M1388 Sky27 2020-01-04 00:00:00 PLAT NULL NULL NULL NULL NULL NULL
SQL
복사
Upper: 7. JOIN