TIL 2021.07.22 | (SQL) JOIN

오늘은 오답노트 느낌이 나는 TIL 게시글입니다. 쿼리가 몇 줄만 길어져도 너무 헷갈립니다. 너무 에러가 많이 떴어서 이제 당황하지도 않습니다.😭 어제 TIL을 건너뛴 것을 반성합니다.(T_T)
SQL을 다루는 것이 아직 많이 서툽니다. 틀린 점이나 개선해야할 점을 남겨주시는 것은 언제나 환영입니다. 🙏

● 여름방학 SQL 공부하기
SQL 이론 학습을 위해 SQLD 공부 중 → 9월 中 SQLD 자격 취득이 목표
SQL 학습을 위해 온라인 강의 수강 중: 스파르타 코딩클럽

TIL 2021.07.22 start!

1. 여러 테이블을 연결해주는 Join

1) Join 란?

▶두 테이블의 공통된 정보 (key값)를 기준으로 테이블을 연결해서 한 테이블처럼 보는 것을 의미. → 집합관계

▶엑셀의 vlookup 역할을 함.

2) Join의 종류

▶left join (NULL 즉, 빈 필드도 모두 나옴)

: A와 B는 각각의 테이블을 의미. 둘 사이의 겹치는 부분은, 뭔가 테이블 A와 B의 key 값이 연결되는 부분.

select * from users u 
left join point_users p on u.user_id = p.user_id

▶inner join (교집합으로 빈 필드는 나오지 않음)

: left join은 순서가 중요하지만 inner join은 교집합이기 때문에 순서가 중요하진 않음.

select * from users u 
inner join point_users p on u.user_id = p.user_id

3) 쿼리 실행 순서

▶from → join → select
▶from → join → where → group by → select

select u.name, count(u.name) as count_name from orders o
inner join users u
on o.user_id = u.user_id 
where u.email like '%naver.com'
group by u.name

2. 오늘의 연습💛

#퀴즈1. 결제 수단별 유저 포인트의 평균값 구해보기

#나의 첫 답안
select pu.point, avg(*) from point_users pu
inner join orders o on o.user_id = pu.user_id
where o.payment_method
group by pu.point

#정답
select o.payment_method, round(avg(pu.point),2) from point_users pu
inner join orders o on o.user_id = pu.user_id
group by o.payment_method
  1. ~별 : group by / 결제수단별: group by payment_method
  2. 결제수단을 선택하고 그 결제 수단의 포인트의 평균값이니,
    select o.payment_method, avg(pu.point) from point_users pu
    ❗ 제발 머리로 글을 써보고 쿼리 작성하기 ❗

#퀴즈2. 결제하고 수업을 시작하지 않은 유저들을 성씨별로 세어보기
#안한 사람 0으로 표기, 한 사람 1로 표기 되어 있음

#나의 첫 답안
select u.name, count(is_registered) from enrolleds e
inner join users u on u.user_id = e.user_id
group by u.name

#정답
select u.name, count(*) as cnt from enrolleds e
inner join users u on u.user_id = e.user_id
where e.is_registered = 0
group by u.name
order by count(*) des
  1. 수강을 하지 않은 사람만 따로 모아서 세어야하니까,
    where e.is_registered = 0

#퀴즈3. 과목별로 시작하지 않은 유저들을 세어보기

#나의 첫 답안
select c.title, count(*) as cnt from courses c
inner join enrolleds e on e.course_id = c.course_id
where e.is_registered = 0
group by c.title

#정답
select c.course_id, c.title, count(*) as cnt_nonstart from courses c
inner join enrolleds e on e.course_id = c.course_id
where e.is_registered = 0
group by c.course_id

#퀴즈4. 웹개발, 앱개발 종합반의 week별 체크인 수를 세어보기.

#나의 첫 답안
select c.course_id, c.title, count(ch.week) as cnt from courses c
inner join checkins ch on ch.course_id = c.course_id
group by ch.week

#정답
select c.title, ch.week, count(*) as cnt from courses c
inner join checkins ch on ch.course_id = c.course_id
group by c.title, ch.week
order by c.title, ch.week

웹개발, 앱개발 종합반 week : group by A, B

#퀴즈5. 퀴즈 4번에서 8월 1일 이후에 구매한 고객들만 추출

#나의 첫 답안
select c1.title, c2.week, count(*) as cnt from courses c1
inner join checkins c2 on c2.course_id = c1. course_id
inner join orders o on o.user_id = c2.user_id
where o.created_at()
group by c1.title, c2.week
order by c1.title, c2.week

#정답
select c1.title, c2.week, count(*) as cnt from courses c1
inner join checkins c2 on c2.course_id = c1. course_id
inner join orders o on o.user_id = c2.user_id
where o.created_at >= '2020-08-01'
group by c1.title, c2.week 
order by c1.title, c2.week

<= '날짜' / >='날짜' / bitween '날짜' and '날짜'


left join

#not NULL/ NULL

select u.name, COUNT(*) as cnt from users u
left join point_users pu on u.user_id = pu.user_id
where pu.point_user_id is not NULL
group by u.name

#퀴즈6. 7월10일~7월19일에 가입한 고객 중, 포인트를 가진 고객의 숫자, 그리고 전체 숫자, 그리고 비율

#나의 첫 답안
select pu.point_user_id, count(*) as cnt from users u
left join point_users pu on u.user_id = pu.user_id
where u.created_at between '2020-07-10' and '2020-07-19'

#정답
select count(pu.point_user_id) as pnt_user_cnt, 	
       count(u.user_id) as tot_user_cnt, 
       round(count(pu.point_user_id)/count(u.user_id),2) as ratio 
from users u
left join point_users pu on u.user_id = pu.user_id
where u.created_at between '2020-07-10' and '2020-07-20'


숙제
#enrolled_id별 수강완료(done=1)한 강의 갯수를 세어보고, 완료한 강의 수가 많은 순서대로 정렬해보기,user_id도 같이 출력 되어야한다.

#나의 첫 답안
select e.enrolled_id, e.user_id, 
       count(ed.done) as max_count from enrolleds e
inner join enrolleds_detail ed on ed.enrolled_id = e.enrolled_id
group by ed.enrolled_id, ed.done
order by ed.done

#정답
select e.enrolled_id, e.user_id, 
       count(*) as max_count
from enrolleds e
inner join enrolleds_detail ed on ed.enrolled_id = e.enrolled_id
where ed.done = 1
group by e.enrolled_id, e.user_id
order by max_count desc

where ed.done = 1

3. 결과물을 합쳐주는 UNION

Select를 두 번 할 게 아니라, 한번에 모아서 보고싶은 경우.
단, 내부정렬 order by가 되지 않기 때문에 서브쿼리를 활용해야함.

(
	select '7월' as month, c.title, c2.week, count(*) as cnt from checkins c2
	inner join courses c on c2.course_id = c.course_id
	inner join orders o on o.user_id = c2.user_id
	where o.created_at < '2020-08-01'
	group by c2.course_id, c2.week
  order by c2.course_id, c2.week
)
union all
(
	select '8월' as month, c.title, c2.week, count(*) as cnt from checkins c2
	inner join courses c on c2.course_id = c.course_id
	inner join orders o on o.user_id = c2.user_id
	where o.created_at > '2020-08-01'
	group by c2.course_id, c2.week
  order by c2.course_id, c2.week
)

좋은 웹페이지 즐겨찾기