나의 답:
SELECT FH.FLAVOR FROM FIRST_HALF AS FH
JOIN ICECREAM_INFO AS II
ON FH.FLAVOR = II.FLAVOR
WHERE FH.TOTAL_ORDER > 3000 AND II.INGREDIENT_TYPE = 'fruit_based'
ORDER BY FH.TOTAL_ORDER DESC;
데이터를 주제에 따라 겹치지 않게 효율적인 구조로 정규화를 해서 테이블을 분리했다면,
조회할때는 두개 이상의 테이블에서 데이터를 묶어 가져오는 조인을 사용한다.
JOIN ON 구문의 위치는 WHERE 전이어야 한다.
기준테이블에 추가로 컬럼을 합쳐 테이블을 형성한 뒤
조건문으로 정제가 시작되는 것이다.
JOIN 사용시 가독성을 위해 주로 테이블에 별칭을 붙혀주고,
컬럼 사용시 어떤 테이블의 컬럼인지 별칭.~을 붙혀주는 것이 좋다.
ICECREAM_INFO 테이블의 FLAVOR는
FIRST_HALF테이블 FLAVOR의 외래키다. (조인하는 테이블은 주로 일대다 관계(기본키-외래키))
= ICECREAM_INFO 테이블에서 FLAVOR는 기본키이다.
JOIN에는 INNER JOIN, (LEFT / RIGHT) OUTER JOIN, FULL JOIN 이 있다.
가장 많이 사용하는건 INNER JOIN이다. INNER를 생략해도 이너조인으로 인식한다.
위의 예제는 OUTER JOIN을 이해하기 좋은 케이스는 아니다.
왜냐면 합치는 기준컬럼(FLAVOR)에 대한 모든 경우가 ICECREAM_INFO테이블에 들어있기 때문이다.
아래의 새로운 케이스로 살펴보자.
-- Customers 테이블
| CustomerID | CustomerName |
|------------|--------------|
| 1 | John |
| 2 | Jane |
| 3 | Bob |
| 4 | Alice |
-- Orders 테이블
| OrderID | CustomerID | OrderDate |
|---------|------------|------------|
| 101 | 1 | 2024-01-15 |
| 102 | 2 | 2024-01-20 |
| 103 | 1 | 2024-02-10 |
| 105 | 5 | 2024-03-05 |
위의 두개 테이블을 보면 바로
Order테이블이 기준테이블이 되고, CustomersID를 기준으로 Customers테이블을 조인하겠구나 라는 생각이 든다.
1. INNER JOIN
SELECT o.OrderID, o.OrderDate,
c.CustomerID, c.CustomerName
FROM Orders o
INNER JOIN Customers c ON o.CustomerID = c.CustomerID;
-- 결과
| OrderID | OrderDate | CustomerID | CustomerName |
|---------|------------|------------|--------------|
| 101 | 2024-01-15 | 1 | John |
| 102 | 2024-01-20 | 2 | Jane |
| 103 | 2024-02-10 | 1 | John |
두 테이블의 교집합에 해당하는 데이터(레코드)만 조회가 된다.
2. LEFT OUTER JOIN
SELECT o.OrderID, o.OrderDate,
c.CustomerID, c.CustomerName
FROM Orders o
LEFT JOIN Customers c ON o.CustomerID = c.CustomerID;
-- 결과
| OrderID | OrderDate | CustomerID | CustomerName |
|---------|------------|------------|--------------|
| 101 | 2024-01-15 | 1 | John |
| 102 | 2024-01-20 | 2 | Jane |
| 103 | 2024-02-10 | 1 | John |
| 105 | 2024-03-05 | NULL | NULL |
기준테이블의 데이터(레코드)들은 모두 조회되고,
거기에 해당하는 Orders테이블의 데이터는 없으니 NULL처리가 된다.
(교집합에 해당하는 데이터 + 기준테이블 쪽 데이터)
3. RIGHT OUTER JOIN
SELECT o.OrderID, o.OrderDate,
c.CustomerID, c.CustomerName
FROM Orders o
FULL OUTER JOIN Customers c ON o.CustomerID = c.CustomerID;
-- 결과
| OrderID | OrderDate | CustomerID | CustomerName |
|---------|------------|------------|--------------|
| 101 | 2024-01-15 | 1 | John |
| 102 | 2024-01-20 | 2 | Jane |
| 103 | 2024-02-10 | 1 | John |
| NULL | NULL | 3 | Bob |
| NULL | NULL | 4 | Alice |
조인 테이블의 데이터(레코드)들은 모두 조회되고,
거기에 해당하는 Orders테이블의 데이터는 없으니 NULL처리가 된다.
(교집합에 해당하는 데이터 + 조인테이블 쪽 데이터)
4. FULL JOIN
SELECT o.OrderID, o.OrderDate,
c.CustomerID, c.CustomerName
FROM Orders o
FULL OUTER JOIN Customers c ON o.CustomerID = c.CustomerID;
-- 결과
| OrderID | OrderDate | CustomerID | CustomerName |
|---------|------------|------------|--------------|
| 101 | 2024-01-15 | 1 | John |
| 102 | 2024-01-20 | 2 | Jane |
| 103 | 2024-02-10 | 1 | John |
| 105 | 2024-03-05 | NULL | NULL |
| NULL | NULL | 3 | Bob |
| NULL | NULL | 4 | Alice |
두 테이블간의 합집합 원소(레코드)를 모두 보여준다.
만약 Customers 테이블을 기준으로 조인한다면 어떨지도 살펴보자.
1. INNER JOIN >> 동일
SELECT c.CustomerID, c.CustomerName, o.OrderID, o.OrderDate
FROM Customers c
INNER JOIN Orders o ON c.CustomerID = o.CustomerID;
-- 결과
| CustomerID | CustomerName | OrderID | OrderDate |
|------------|--------------|---------|------------|
| 1 | John | 101 | 2024-01-15 |
| 1 | John | 103 | 2024-02-10 |
| 2 | Jane | 102 | 2024-01-20 |
2. LEFT OUTER JOIN >> 위의 RIGHT OUTER JOIN과 동일
SELECT c.CustomerID, c.CustomerName, o.OrderID, o.OrderDate
FROM Customers c
LEFT JOIN Orders o ON c.CustomerID = o.CustomerID;
-- 결과
| CustomerID | CustomerName | OrderID | OrderDate |
|------------|--------------|---------|------------|
| 1 | John | 101 | 2024-01-15 |
| 1 | John | 103 | 2024-02-10 |
| 2 | Jane | 102 | 2024-01-20 |
| 3 | Bob | NULL | NULL |
| 4 | Alice | NULL | NULL |
3. RIGHT OUTER JOIN >> 위의 LEFT OUTER JOIN과 동일
SELECT c.CustomerID, c.CustomerName, o.OrderID, o.OrderDate
FROM Customers c
RIGHT JOIN Orders o ON c.CustomerID = o.CustomerID;
-- 결과
| CustomerID | CustomerName | OrderID | OrderDate |
|------------|--------------|---------|------------|
| 1 | John | 101 | 2024-01-15 |
| 1 | John | 103 | 2024-02-10 |
| 2 | Jane | 102 | 2024-01-20 |
| NULL | NULL | 105 | 2024-03-05 |
4. FULL JOIN >> 동일
SELECT c.CustomerID, c.CustomerName, o.OrderID, o.OrderDate
FROM Customers c
FULL OUTER JOIN Orders o ON c.CustomerID = o.CustomerID;
-- 기준
| CustomerID | CustomerName | OrderID | OrderDate |
|------------|--------------|---------|------------|
| 1 | John | 101 | 2024-01-15 |
| 1 | John | 103 | 2024-02-10 |
| 2 | Jane | 102 | 2024-01-20 |
| 3 | Bob | NULL | NULL |
| 4 | Alice | NULL | NULL |
| NULL | NULL | 105 | 2024-03-05 |