나를 금요일 ~ 일요일 / + 월요일까지 총 4일을 정신적인 고통을 받게 한 주범.
4일 동안의 고통을 한번 정리해보겠습니다.
제약 조건은 반드시 [서브쿼리], [조인], [그룹], [그룹 조건] 을 써야한다는 것
1번 문제 같은 경우 제약조건 없이 그냥 쓴다면?
SELECT c.CustomerName, COUNT(o.CustomerID), COALESCE(SUM(o.TotalAmount), 0) as total_price FROM customers c LEFT OUTER JOIN orders o ON c.CustomerID = o.CustomerID GROUP BY c.CustomerName ORDER BY COUNT(o.CustomerID) DESC
이렇게 되겠지만.. 제약조건을 지켜야 하기에 제약조건을 포함해서 작업해본다면...
계획
- 일단, 고객이름, 주문횟수, 총 금액을 파편별로 정리하기
- 그거를 가지고 그룹 HAVING 절에 서브쿼리를 넣기...
SELECT c.CustomerName, sub.count_id, sub.total_amount FROM customers c LEFT OUTER JOIN orders o ON c.CustomerID = o.CustomerID GROUP BY c.CustomerName HAVING SUM(o.TotalAmount) = ( SELECT COUNT(o.CustomerID) as count_id, SUM(o.TotalAmount) as total_amount FROM customers c LEFT OUTER JOIN orders o ON c.CustomerID = o.CustomerID ) sub계속해서 1~2일 차에 HAVING 절에다가 자꾸 서브쿼리 넣고 오류가 뜨는데도 구문이 잘못되었나 싶어서 계속 해서 시도했던 것이다.
HAVING SUM(o.TotalAmount) = ( SELECT MAX(o1.TotalAmount) FROM customers c1 LEFT OUTER JOIN orders o1 ON c.CustomerID = o.CustomerID ) a
원래 내가 이해했던 [GROUP BY / HAVING] 은
GROUP BY 로 그룹을 묶고
HAVING 으로 그룹에 대한 조건을 주는 것.
그래서 GROUP 한 결과에서 o.TotalAmount 가 Null 인 값은 0으로 출력하면 되겠다!!"
박치기식으로 하다보면 찾아낼거라 생각했습니다.
그렇게 하다보면 언젠간 찾아낼꺼라고 생각했습니다.
바보같은 생각이였습니다...
조금 더 찾아봤으면 됐을텐데 아쉬움은 있지만 후회는 하지않습니다.
이걸 계기로 저는 GROUP BY HAVING 에 대해서 다는 아니지만 80%는 이해했습니다.
SQL 문법을 읽는 능력도 같이 길러졌구요.
그래서 조건을 바꾸기로 했습니다.
1~3일 차 까지 저러고 있었습니다.
2 번째 계획 ( 4일차 )
- 서브쿼리는 FROM 쪽으로 빼고,
- HAVING 절로 Null을 필터링 하자.
SELECT a.name, a.count_id, a.total_amount FROM ( SELECT c.CustomerName as name, COUNT(o.CustomerID) as count_id, SUM(o.TotalAmount) as total_amount FROM customers c LEFT OUTER JOIN orders o ON c.CustomerID = o.CustomerID GROUP BY c.CustomerName HAVING IF (SUM(o.TotalAmount) IS NULL, 0, SUM(o.TotalAmount)) ) a ORDER BY a.count_id DESC
왜 안될까... 생각을 계속 하고 있다가... HAVING 을 빼보니
왜 HAVING 을 빼니까 작동을 할까?
고민하고 고민하고 안되겠어서 직접 찾아보기로 했습니다.
정리하면...
HAVING 절의 동작 방식은 TRUE인 조건을 만족하는 행만 남긴다는 것입니다
SUM(o.TotalAmount)가 NULL이면 0이 됩니다.
그러나 HAVING 절에서 0을 넣어버리면, SQL은 "조건식 자체가 참이냐?"를 평가합니다.
HAVING 0은 FALSE로 평가되므로, 해당 행이 제거됩니다.
따라서 NULL → 0으로 변환했음에도 불구하고 결과에서 사라집니다.
3 번 계획
- 오케이 ! 모든 걸 다 파악했다.
SELECT a.name, a.count_id, a.total_amount FROM ( SELECT c.CustomerName as name, COUNT(o.CustomerID) as count_id, COALESCE(SUM(o.TotalAmount), 0) as total_amount FROM customers c LEFT OUTER JOIN orders o ON c.CustomerID = o.CustomerID GROUP BY c.CustomerName HAVING total_amount >= 0 ) a ORDER BY a.count_id DESC이렇게 하면 음수는 표시되지 않고 최소 0 이상인 TotalAmount가 표시된다.
드디어 4일만에 4-1 문제를 해결했다.
원래 알던 사실
바뀐 사실
논리적 평가 이다.