데이터 분석 팀에서 우유와 요거트를 동시에 구입한 장바구니가 있는지 확인하려고 합니다.
아래 두 SQL문 중 어떤 것이 올바른지 비교해 봅시다.
SELECT cart_id
FROM cart_products
WHERE name IN ('Milk') or name IN ('Yogurt')
GROUP BY cart_id
HAVING COUNT(DISTINCT name) >= 2
ORDER BY cart_id;
GROUP BY cart_id로 장바구니별 그룹화.
COUNT(DISTINCT name)으로 그 장바구니 안에 있는 서로 다른 상품 종류 수를 셈.
Milk와 Yogurt가 모두 있으면 DISTINCT name의 개수가 2가 되어 조건 만족.
SELECT cart_id
FROM cart_products
WHERE name IN ('Milk', 'Yogurt')
GROUP BY cart_id
HAVING COUNT(DISTINCT cart_id) >= 2
ORDER BY cart_id;
GROUP BY cart_id 후에는 그 그룹 안의 cart_id 값이 하나뿐.
따라서 COUNT(DISTINCT cart_id)는 항상 1 → >= 2 조건을 만족할 수 없음.
우리가 세야 하는 건 cart_id의 종류가 아니라 상품명(name)의 종류.
SELECT cart_id
FROM cart_products
WHERE name IN ('Milk', 'Yogurt')
GROUP BY cart_id
HAVING COUNT(DISTINCT name) = 2
ORDER BY cart_id;
1) 셀프 조인 방식
SELECT DISTINCT c1.cart_id
FROM cart_products c1
JOIN cart_products c2
ON c1.cart_id = c2.cart_id
WHERE c1.name = 'Milk'
AND c2.name = 'Yogurt'
ORDER BY c1.cart_id;
2) 조건 합 집계 방식
SELECT cart_id
FROM cart_products
GROUP BY cart_id
HAVING SUM(CASE WHEN name = 'Milk' THEN 1 ELSE 0 END) > 0
AND SUM(CASE WHEN name = 'Yogurt' THEN 1 ELSE 0 END) > 0
ORDER BY cart_id;
정리
1) 집계 조건 필터에서는 COUNT(DISTINCT name)처럼 의미 있는 컬럼을 기준으로 세야 한다.
2) GROUP BY 후 COUNT(DISTINCT 그룹키)는 대부분 1이므로 조건 필터에 부적합.
3) 같은 문제를 다양한 방식(집계, 조인, 조건 합)으로 풀어보면 SQL 사고력이 빨라진다.