데이터로그😎
[MySQL] JOIN 🆚 서브쿼리 본문
*모든 글의 내용은 아래의 사이트를 참고하여 작성했습니다.
서브쿼리(Subquery) vs 조인(JOIN)
1. 서브쿼리
- 하나의 쿼리 안에 다른 쿼리가 포함된 것을 말한다.
- 메인 쿼리라 불리는 외부 쿼리가 있고, 외부 쿼리 내에 다른 내부 쿼리문이 있다.
2. 조인(JOIN)
- 여러개의 쿼리가 필요하지 않다.
- 2개 이상의 테이블을 특정 기준에 따라 연결하고, 연결한 최종 테이블로부터 열을 조회하도록 하는 기능이다.
🚨서브쿼리는 가독성이 좋다. 그러나 JOIN에 비해 성능이 좋진 않다.
예시
product와 sale테이블이 있다. 아래의 3가지 질문에 답해보며 서브쿼리와 조인을 비교해볼 것이다.
[product 테이블]
id | name | cost | year | city |
1 | chair | 245.00 | 2017 | Chicago |
2 | armchair | 500.00 | 2018 | Chicago |
3 | desk | 900.00 | 2019 | Los Angeles |
4 | lamp | 85.00 | 2017 | Cleveland |
5 | bench | 2000.00 | 2018 | Seattle |
6 | stool | 2500.00 | 2020 | Austin |
7 | tv table | 2000.00 | 2020 | Austin |
[sale 테이블]
id | product_id (외래키) | price | year | city |
1 | 2 | 2000.00 | 2020 | Chicago |
2 | 2 | 590.00 | 2020 | New York |
3 | 2 | 790.00 | 2020 | Cleveland |
5 | 3 | 800.00 | 2019 | Cleveland |
6 | 4 | 100.00 | 2020 | Detroit |
7 | 5 | 2300.00 | 2019 | Seattle |
8 | 7 | 2000.00 | 2020 | New York |
# 문제1) 2,000달러에 팔린 product의 이름과 가격을 알아보자
① JOIN
SELECT P.name, P.cost
FROM sale S
JOIN product P
ON S.product_id = P.id
WHERE S.price = 2000 ;
② 서브쿼리
SELECT name, cost
FROM product
WHERE id IN (SELECT product_id
FROM sale
WHERE price = 2000);
**서브쿼리를 WHERE문 안에 놓을 때는 product 테이블의 모든 id와 서브쿼리문의 product_id를 비교할 때마다 서브쿼리문이 실행된다. 이 때, 비교할 때마다 내부 쿼리를 계속 반복해서 실행하기 때문에 속도, 성능이 낮아진다.
결과
name | cost |
armchair | 500.00 |
tv table | 2000.00 |
# 문제2) 판매된 상품의 이름과 가격을 알아보자
① JOIN
SELECT DISTINCT P.name, P.cost
FROM product P
JOIN SALE S
ON P.id = S.product_id;
② 서브쿼리
SELECT name, cost
FROM product
WHERE id IN (SELECT DISTINCT product_id
FROM sale);
결과
name | cost |
armchair | 500.00 |
desk | 900.00 |
lamp | 85.00 |
bench | 2000.00 |
tv table | 2000.00 |
# 문제 3) 판매되지 않은 상품들의 이름과 가격을 알아보자
① JOIN
SELECT DISTINCT P.name, P.cost
FROM product P
LEFT JOIN sale S
ON P.id = S.product_id
WHERE S.product_id IS NULL;
LEFT JOIN을 사용하게 되면 product 테이블의 모든 행은 보여지고, product 테이블에 있는 id와 동일한 product_id를 가진 sale 테이블의 row는 정상적으로 보여지게 된다. 그러나 product 테이블에는 있지만 sale 테이블에는 없는 상품은 NULL로 보여지게 된다. 아래와 같이 말이다.
sale테이블에는 2,3,4,5,7 상품만 존재하고 1,6은 존재하지 않는다. 따라서 id가 1, 6인 상품은 sale 테이블에는 존재하지 않기 때문에 sale테이블의 id, product_id, price, year, city 정보는 최종 테이블에서 null로 보여지는 것이다.
| id | name | cost | year | city | id | product_id | price | year | city |
|----|-----------|--------|------|------------|-----|------------|---------|------|------------|
| 1 | chair | 245.00 | 2017 | Chicago | null| null | null | null | null |
| 2 | armchair | 500.00 | 2018 | Chicago | 1 | 2 | 2000.00 | 2020 | Chicago |
| 2 | armchair | 500.00 | 2018 | Chicago | 2 | 2 | 590.00 | 2020 | New York |
| 2 | armchair | 500.00 | 2018 | Chicago | 3 | 2 | 790.00 | 2020 | Cleveland |
| 3 | desk | 900.00 | 2019 | Los Angeles| 5 | 3 | 800.00 | 2019 | Cleveland |
| 4 | lamp | 85.00 | 2017 | Cleveland | 6 | 4 | 100.00 | 2020 | Detroit |
| 5 | bench | 2000.00| 2018 | Seattle | 7 | 5 | 2300.00 | 2019 | Seattle |
| 6 | stool | 2500.00| 2020 | Austin | null| null | null | null | null |
| 7 | tv table | 2000.00| 2020 | Austin | 8 | 7 | 2000.00 | 2020 | New York |
LEFT JOIN을 실행한 후 WHERE문에서 sale 테이블의 product_id가 NULL인 상품들만 골라서 보려한다. 즉, 판매되지 않은 상품들을 의미한다. 이들은 id가 1, 6인 상품일테니 최종 테이블은 아래와 같다.
결과
name | cost |
chair | 245.00 |
stool | 2500.00 |
② 서브쿼리
SELECT name, cost
FROM product
WHERE id NOT IN (SELECT DISTINCT product_id
FROM sale)
그러나, JOIN과 SUBQUERY가 서로 대체될 수 없는 경우도 있다.이 때는 SUBQUERY문에 집계가 실행될 때이다.
*서브쿼리 내에서 집계된 단일 값을 WHERE 절에서 외부 쿼리의 값과 비교할 때
SELECT name
FROM product
WHERE cost < (SELECT AVG(price) FROM sale);
SELECT city, sum_price
FROM
(
SELECT city, SUM(price) as sum_price
FROM sale
GROUP BY city
) s
WHERE sum_price < 2100;
'SQL > MySQL' 카테고리의 다른 글
[MySQL] 데이터 모델링 (0) | 2024.01.10 |
---|---|
[MySQL] 데이터베이스 & 유저 생성 (0) | 2024.01.01 |
[MySQL] 테이블 생성, 입력, 수정, 삭제 (0) | 2023.12.29 |
[MySQL] 테이블 정보 확인 (0) | 2023.12.29 |
[MySQL] 날짜형식 관련 함수 (0) | 2023.12.29 |