
[주제]
[아티클 요약]
공부를 한다는 것은 문제 해결의 연속
피아노 연습처럼, 막막함을 견디고 꾸준히 시도를 해야 성장한다!
[인사이트]
스스로 공부하면서 쉼표같은 아주 사소한 문제를 찾지 못한 적이 있는데, 질문 전 체크리스트를 통해 오류가 났을 때 차근차근 문제를 해결할 수 있을 것 같다. 아직 공식 문서나 영문 자료들을 확인할 정도로 sql을 잘 몰라서 혼자 공부할 때는 velog에 검색하거나 한글로 검색해 공부했다. 추후 스스로 공부할 때 유용할 것 같은 정보와 사이트를 알게 되어 도움일 될 것 같다. 또 데이터리안이라는 사이트를 알게 되어 블로그에서 많은 정보를 얻을 수 있을 것 같아 만족스럽다. 아티클에서 악기를 연습하는 예시를 들었는데 굉장히 공감이 됐다. 막막함을 견디며 포기하지 않고 꾸준히 공부하겠다고 다짐했다.
# 평균 구하기 예시
SELECT
restaurant_name
# 사용할 수 없는 데이터 제거하지 않고 계산할 경우 MySQL 은 0으로 간주
, AVG(rating) average_of_rating
# rating에 'Not given'이 아닐 경우에만 평균 계산, 아니면 NULL
, AVG(IF(rating<>'Not given', rating, NULL)) average_of_rating2
FROM food_orders
GROUP BY 1;

NULL 처리 하지 않으면 사용할 수 없는 데이터도 분모로 취급되어 값이 작아짐
처리 후 사용 가능한 데이터만 계산해 값이 커짐
NULL값 제외 방법
- IF절로 NULL 값 만들어주기
- WHERE 컬럼명 IS NOT NULL
대체값 사용법
# 다른 값이 있을 때 조건문 이용하기 IF(컬럼명 원하는 조건, 그대로 출력, 대체값) IF(rating >=1, rating, 대체값) # null 값일 때, 대체값으로 변경 COALESCE(컬럼명, 대체값)
상식적이지 않은 데이터 예시
상식적이지 않은 데이터를 다루기 위해 조건문으로 값의 범위를 지정하기
CASE문 활용
피벗 테이블
2개 이상의 기준으로 데이터를 집계할 때, 보기 쉽게 배열하여 보여주는 것

만드는 법
베이스 데이터 만들기 -> 피벗 뷰 만들기
15~20시 사이, 20시 주문건수 기준 내림차순
먼저 베이스 데이터 만들기
나의 풀이
SELECT
restaurant_name
, SUBSTR(time, 1, 2) hour
, COUNT(quantity) count_quantity
FROM
(#서브쿼리로 테이블 합치기
SELECT
fo.restaurant_name
, fo.quantity
, p.time
FROM food_orders fo
LEFT JOIN payments p
ON fo.order_id = p.order_id
) join_table
WHERE SUBSTR(time, 1, 2) BETWEEN 15 AND 20
# 음식점별, 시간별 정렬
GROUP BY 1,2
# 20시 주문건수 기준 내림차순 정렬
ORDER bY 2 DESC
답지와 비교
select a.restaurant_name,
substring(b.time, 1, 2) hh,
count(1) cnt_order
from food_orders a inner join payments b on a.order_id=b.order_id
where substring(b.time, 1, 2) between 15 and 20
group by 1, 2
생각해보니 서브쿼리에서 딱히 미리 계산할 내용이 없어서 안쓰고 답지처럼 하는게 나을 것 같았다. 지난 시간에 배운거라 아무 생각없이 그냥 쓴 느낌이라 잘 생각하고 써야겠다. 그리고 정렬은 미리 하지 않고 피벗 테이블 만든 이후에 하는 것 같다. 아직 피벗테이블 만드는 법은 몰라서 강의를 보면서 공부했다.
피벗 테이블 만드는 방법
SELECT # 행 축 지정 , restaurant_name, # 열 축 지정 # MAX를 쓰는 이유 : 시간대(hh)별 데이터를 유일한 값으로 뽑아내는 역할 # 피벗테이블 형식으로 만들기 위해! 쓴다고 이해 , MAX(IF(hh='15', cnt_order, 0)) "15" , MAX(IF(hh='16', cnt_order, 0)) "16" , MAX(IF(hh='17', cnt_order, 0)) "17" , MAX(IF(hh='18', cnt_order, 0)) "18" , MAX(IF(hh='19', cnt_order, 0)) "19" , MAX(IF(hh='20', cnt_order, 0)) "20" FROM ( # 아까 만든 베이스 데이터를 서브쿼리로 만들기 SELECT fo.restaurant_name, substring(p.time, 1, 2) hh, count(1) cnt_order FROM food_orders fo INNER JOIN payments p ON fo.order_id = p.order_id WHERE substring(p.time, 1, 2) BETWEEN 15 AND 20 GROUP BY 1, 2 ) base_data # MAX 썼으니까 GROUP BY로 정렬 GROUP BY 1 # 최종 정렬 20시 기준 내림차순 ORDER BY 7 DESC;MAX를 왜 쓰는지 설명을 안하고 넘어가서 GPT에 질문했는데 답변이 좀 어려웠다. 특정 조건의 값을 가져오면서 동시에 여러 값을 한 행으로 정리하려면 집계 함수가 필요하기 때문이라고 이해했다. 완벽히 이해는 안되지만 일단 넘어가고 필요하면 다시 찾아봐야겠다.
나이는 10~59세 사이, 연령 순으로 내림차순
SELECT
gender
, MAX(IF(age=10, count_order, 0)) "10s"
, MAX(IF(age=20, count_order, 0)) "20s"
, MAX(IF(age=30, count_order, 0)) "30s"
, MAX(IF(age=40, count_order, 0)) "40s"
, MAX(IF(age=50, count_order, 0)) "50s"
FROM
(
SELECT
COUNT(fo.quantity) count_order
, c.gender
, CASE
WHEN c.age < 20 THEN 10
WHEN c.age BETWEEN 20 AND 29 THEN 20
WHEN c.age BETWEEN 30 AND 39 THEN 30
WHEN c.age BETWEEN 40 AND 49 THEN 40
ELSE 50
END AS age
FROM food_orders fo
INNER JOIN customers c
ON fo.customer_id = c.customer_id
WHERE c.age BETWEEN 10 AND 59
GROUP BY 2,3
)base_data
GROUP BY 1
ORDER BY 2;
몇 번 오류가 났지만 성공했다.
근데 답지엔 가로 세로 축이 반대로 되어있다.
생각해보니 연령순으로 내림차순이라 나이가 행 줄이어야 한다...
# 축 바꿈
SELECT
age
, MAX(IF(gender='male', count_order, 0)) "Male"
, MAX(IF(gender='female', count_order, 0)) "Female"
FROM
(
SELECT
COUNT(fo.quantity) count_order
, c.gender
, CASE
WHEN c.age < 20 THEN 10
WHEN c.age BETWEEN 20 AND 29 THEN 20
WHEN c.age BETWEEN 30 AND 39 THEN 30
WHEN c.age BETWEEN 40 AND 49 THEN 40
ELSE 50
END AS age
FROM food_orders fo
INNER JOIN customers c
ON fo.customer_id = c.customer_id
WHERE c.age BETWEEN 10 AND 59
GROUP BY 2,3
)base_data
GROUP BY 1
ORDER BY 1;

윈도우 함수 실습하다가 시간이 없어서 내일 전부 정리하려고 좀 뺐다. 내일 SQL 마무리하고 문제 풀면서 연휴에 어떻게 할지 계획 좀 세워야겠다. 파이썬 간단히 하고 SQLD 강의를 들으면서 공부를 할지, 달리기 문제 전부 풀어볼지 생각해봐야겠다. 어제 오늘 아티클 내용이 굉장히 도움이 되는 것 같아 좋다. 팀원들이랑 은근 나름 친해진 것 같다... 그래도 같이 공부하는 사람이 있어서 훨씬 수월하다. 부트캠프 신청하길 잘한 것 같다. 제대로 시작하기 전에 사전캠프에서 실력을 많이 키우고 싶다!