프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제의 출처는 위의 링크이다.
문제 설명
다음은 아이스크림 가게의 상반기 주문 정보를 담은 FIRST_HALF 테이블과 아이스크림 성분에 대한 정보를 담은 ICECREAM_INFO 테이블 입니다. FIRST_HALF 테이블 구조는 다음과 같으며, SHIPMENT_ID, FLAVOR, TOTAL_ORDER는 각각 아이스크림 공장에서 아이스크림 가게까지의 출하번호, 아이스크림 맛, 상반기 아이스크림 총주문량을 나타냅니다. FIRST_HALF 테이블의 기본 키는 FLAVOR입니다.
| NAME | TYPE | Nullable |
| SHIPMENT_ID | INT(N) | FALSE |
| FLAVOR | VARCHAR(N) | FALSE |
| TOTAL_ORDER | INT(N) | FALSE |
ICECREAM_INFO 테이블 구조는 다음과 같으며, FLAVOR, INGREDIENT_TYPE은 각각 아이스크림 맛, 아이스크림의 성분 타입을 나타냅니다. INGREDIENT_TYPE에는 아이스크림의 주 성분이 설탕이면 sugar_based라고 입력되고, 아이스크림의 주 성분이 과일이면 fruit_based라고 입력됩니다. ICECREAM_INFO의 기본 키는 FLAVOR입니다. ICECREAM_INFO 테이블의 FLAVOR는 FIRST_HALF 테이블의 FLAVOR의 외래 키입니다.
| NAME | TYPE | Nullable |
| SHIPMENT_ID | VARCHAR(N) | FALSE |
| FLAVOR | VARCHAR(N) | FALSE |
문제
상반기 아이스크림 총주문량이 3,000보다 높으면서 아이스크림의 주 성분이 과일인 아이스크림의 맛을 총주문량이 큰 순서대로 조회하는 SQL 문을 작성해주세요.
예시
예를 들어 FIRST_HALF 테이블이 다음과 같고
| SHIPMENT_ID | FLAVOR | TOTAL_ORDER |
| 101 | chocolate | 3200 |
| 102 | vanilla | 2800 |
| 103 | mint_chocolate | 1700 |
| 104 | caramel | 2600 |
| 105 | white_chocolate | 3100 |
| 106 | peach | 2450 |
| 107 | watermelon | 2150 |
| 108 | mango | 2900 |
| 109 | strawberry | 3100 |
| 110 | melon | 3150 |
| 111 | orange | 2900 |
| 112 | pineapple | 2900 |
ICECREAM_INFO 테이블이 다음과 같다면
| FLAVOR | INGREDIENT_TYPE |
| chocolate | sugar_based |
| vanilla | sugar_based |
| mint_chocolate | sugar_based |
| caramel | sugar_based |
| white_chocolate | sugar_based |
| peach | fruit_based |
| watermelon | fruit_based |
| mango | fruit_based |
| strawberry | fruit_based |
| melon | fruit_based |
| orange | fruit_based |
| pineapple | fruit_based |
상반기 아이스크림 총주문량이 3,000보다 높은 아이스크림 맛은 chocolate, strawberry, melon, white_chocolate입니다.
이 중에 아이스크림의 주 성분이 과일인 아이스크림 맛은 strawberry와 melon이고 총 주문량이 큰 순서대로 아이스크림 맛을 조회하면 melon, strawberry 순으로 조회되어야 합니다. 따라서 SQL문을 실행하면 다음과 같이 나와야 합니다.
| FLAVOR |
| melon |
| strawberry |
내가 작성한 코드
select FIRST_HALF.FLAVOR
from FIRST_HALF
left join ICECREAM_INFO on FIRST_HALF.FLAVOR = ICECREAM_INFO.FLAVOR
WHERE ICECREAM_INFO.INGREDIENT_TYPE = 'fruit_based' and FIRST_HALF.TOTAL_ORDER > 3000
union
select FIRST_HALF.FLAVOR
from FIRST_HALF
right join ICECREAM_INFO on FIRST_HALF.FLAVOR = ICECREAM_INFO.FLAVOR
WHERE ICECREAM_INFO.INGREDIENT_TYPE = 'fruit_based' and FIRST_HALF.TOTAL_ORDER > 3000
이렇게 풀어낸 과정과 이유
세상에 쉬운 문제는 하나 없다. 참 어려운 건 누구나 다 계획을 갖고 있지만, 그것을 코드로 구현하는 것은 아직 어려운 코테린이의 모오습..

그냥 딱 문제를 보고 들었던 생각은 두 테이블을 조인 시켜서 조건에 맞는 값들을 출력시키는 것을 생각했었다.
그러나 SQLD를 공부하면서 두 테이블을 모두 합치는 것을 FULL OUTER JOIN으로 공부를 했었고 이에 대한 도식은 아래와 같다.

보통은 Oracle의 경우에는 아래와 같이 사용된다.
#오라클의 FULL OUTER JOIN
SELECT a.empno, a.ename, a.job, b.deptno, b.dname
FROM emp a
FULL OUTER JOIN dept b
ON a.deptno = b.deptno
하지만 내가 주로 쓰는 MySQL같은 경우에는 Oracle처럼 저렇게 FULL OUTER JOIN을 쓸 수 없다.
MySQL에서 FULL OUTER JOIN을 쓰려면 아래와 같이 사용해야한다.
#MySQL의 FULL OUTER JOIN
SELECT a.empno, a.ename, a.job, b.deptno, b.dname
FROM emp a
LEFT JOIN dept b ON a.deptno = b.deptno
UNION
SELECT a.empno, a.ename, a.job, b.deptno, b.dname
FROM emp a
RIGHT JOIN dept b ON a.deptno = b.deptno
보다시피, LEFT JOIN과 RIGHT JOIN을 한것들을 모두 UNION시키는 방법이다. 그림으로 설명을 하자면,


이를 모두 합치게 되면(UNION),

여기서 하나를 더 이야기를 해보자면, UNION과 UNION ALL의 차이를 알아야한다.
UNION의 경우에는 LEFT JOIN된 부분과 RIGHT JOIN된 부분 중 교집합 된 부분에서 각각 값이 1개씩 있기에 중복이 발생할텐데,
UNION을 사용하면 중복된 값들을 제거한다. UNION ALL의 경우 중복된 값을 없애지 않고 중복된 값을 그대로 냅두는 차이가 있다.

결과
