본문 바로가기

항해99

23.08.04 항해 99 16기 개강준비과정 2일차 엑셀보다 쉬운 SQL 항해 3, 4주차

오늘은 3주자와 4주차 강의를 들었다

3주차 까지는 어찌어찌 따라갔는데

4주차 강의는 너무 어려웠다 SUBQUERY의 개념이 잘 이해가지 않았다

어디에 어떻게 기입해야 하는지가 복잡하고 어려웠다

나름대로 정리하여 계속 보는 방법 밖엔 없을 것 같다

 

JOIN 테이블과 테이블을 붙이는 것 기준이 가장 중요함

 

LEFT JOIN 어디에 무엇을 붙일 것인지 순서 중요

SELECT * FROM users u (테이블을 별칭으로 만듬)

left join point_users p (붙이는 테이블도 별칭으로 만듬)

on u.user_id = p.user_id (각 테이블에 있는 동일한 별칭을 찾아 연결)

 

710~719일에 가입한 고객 중 포인트를 가진 고객의 숫자, 전체 숫자, 비율을 보고 싶어요!

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'

 

INNER JOIN 교집합 두 개다 포함 되는 것만 나옴

SELECT * FROM users u (테이블을 별칭으로 만듬)

inner join point_users p (붙이는 테이블도 별칭으로 만듬)

on u.user_id = p.user_id (각 테이블에 있는 동일한 별칭을 찾아 연결)

 

checkins 테이블에 courses 테이블 연결해서 통계치 내보기

select c.course_id, c1.title, count(*) as cnt from checkins c

inner join courses c1 on c.course_id = c1.course_id

group by c.course_id

 

point_users 테이블에 users 테이블 연결해서 순서대로 정렬해보기

SELECT p.user_id, u.name, u.email, p.point from point_users p

inner join users u on p.user_id = u.user_id

order by p.point desc

 

네이버 이메일 사용하는 유저의 성씨별 주문건수 세어보기

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

 

결제 수단별 유저 포인트의 평균값 구해보기

SELECT o.payment_method, round(avg(p.point),0) from orders o

inner join point_users p on o.user_id = p.user_id

GROUP by o.payment_method

 

결제 시작하고 시작하지 않은 유저들을 성씨별로 세어보기

SELECT u.name, count(*) as cnt from enrolleds e

inner join users u on e.user_id =u.user_id

where e.is_registered = 0

group by u.name

order by count(*) desc

 

과목별로 시작하지 않은 유저들을 세어보기

SELECT c.course_id, c.title, count(*) as cnt from courses c

inner join enrolleds e on c.course_id = e.course_id

where e.is_registered = 0

group by c.course_id

 

웹개발, 앱개발 종합반의 week 별 체크인 수 세기

SELECT c.title, c1.week, count(*) as cnt from courses c

inner join checkins c1 on c.course_id = c1.course_id

group by c.title, c1.WEEK

order BY c.title, c1.WEEK

 

웹개발, 앱개발 종합반의 week 별 체크인 수 세기 후 81일 이후에 구매한 고객들만 발라내기

SELECT c.title, c1.week, count(*) as cnt from courses c

inner join checkins c1 on c.course_id = c1.course_id

inner join orders o on c1.user_id = o.user_id

WHERE o.created_at >='2020-08-01'

group by c.title, c1.WEEK

order BY c.title, c1.WEEK

 

enrolled_id별 수강완료(done=1)한 강의 갯수를 세어보고, 완료한 강의 수가 많은 순서대로 정렬해보기.

user_id도 같이 출력되어야 한다.

select e.enrolled_id,e.user_id, count(*) as cnt

from enrolleds e

inner join enrolleds_detail ed on e.enrolled_id = ed.enrolled_id

where ed.done = 1

group by e.enrolled_id, e.user_id

order by cnt desc

 

union select를 한번에 모아서 보고 싶을 때 두 개를 붙인다

(

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

)

 

subquery 원하는 데이터를 더 쉽게 얻어 보기 쿼리 안의 쿼리라는 의미

 

SELECT u.user_id , u.name, u.email from users u

inner join orders o

on u.user_id = o.user_id

WHERE o.payment_method ='kakaopay'

 

위와 아래 동일한 결과 나옴 (번 결과 먼저 나오고 밖에 있는 것을 실행함)

 

SELECT user_id, name, email from users

WHERE user_id in (

select user_id from orders

WHERE payment_method ='kakaopay'

)

 

WHERE에 들어가는 SUBQUERY

SELECT user_id, name, email from users

WHERE user_id in (

select user_id from orders

WHERE payment_method ='kakaopay'

)

 

전체 유저의 포인트의 평균보다 큰 유저들의 데이터 추출하기

SELECT * from point_users

where point > (

select avg(point) from point_users

)

 

이씨 성을 가진 유저의 포인트의 평균보다 큰 유저들의 데이터 추출하기 2가지 방법

 SELECT * from point_users

WHERE point > (

SELECT avg(point) from point_users pu

inner join users u on pu.user_id = u.user_id

where u.name='**'

)

 

SELECT * from point_users

WHERE point >(

SELECT avg(point) from point_users pu

WHERE user_id in(

SELECT user_id from users WHERE name = '**'

)

)

 

SELECT에 들어가는 SUBQUERY

SELECT c.checkin_id,

c.user_id,

c.likes,

(

select avg(likes) from checkins

WHERE user_id = c.user_id

) as avg_likes_user

from checkins c

 

checkins 테이블에 course_id 별 평균 likes 수 필드 우측에 붙여보기

SELECT c.checkin_id,

c.course_id,

c.user_id,

c.likes,

(

SELECT avg(likes) from checkins

WHERE course_id = c.course_id

) as course_avg

FROM checkins c

 

checkins 테이블에 과목별 평균 likes 수 필드 우측에 붙여보기

SELECT c.checkin_id,

c1.title,

c.user_id,

c.likes,

(

SELECT avg(likes) from checkins

WHERE course_id = c.course_id

) as course_avg

FROM checkins c

inner join courses c1 on c.course_id = c1.course_id

 

FROM에 들어가는 SUBQUERY

SELECT pu.user_id , pu.point, a.avg_LIKES FROM point_users pu

INNER JOIN(

SELECT user_id, ROUND(AVG(LIKES),1) AS avg_LIKES FROM checkins c

GROUP BY user_id

) a ON pu.user_id = a.USER_ID

 

연습

SELECT c.title,

a.cnt_checkins,

b.cnt_total,

(a.cnt_checkins/b.cnt_total) as ratio

from

(

select course_id, count(DISTINCT(user_id)) as cnt_checkins from checkins

group by course_id

)a

inner join

(

select course_id, count(*) as cnt_total from orders

group by course_id

)b on a.course_id = b.course_id

inner join courses c on a.course_id=c.course_id

  

위에 있는 것을 WITH 절로

with table1 as (

select course_id, count(DISTINCT(user_id)) as cnt_checkins from checkins

group by course_id

), table2 as (select course_id, count(*) as cnt_total from orders

group by course_id )

 

SELECT c.title,

a.cnt_checkins,

b.cnt_total,

(a.cnt_checkins/b.cnt_total) as ratio

from table1 a

inner join table2 b on a.course_id = b.course_id

inner join courses c on a.course_id=c.course_id

 

문자열 문법

문자열 쪼개보기 SELECT user_id , emaiL, SUBSTRING_INDEX(email,'@',1) FROM users (이메일을 @ 기준으로 첫 번째 것만 보여줘)

 

SELECT user_id , emaiL, SUBSTRING_INDEX(email,'@',-1) FROM users (이메일을 @ 기준으로 마지막 것만 보여줘)

 

문자열 일부만 출력하기 SELECT ORDER_NO, created_at, SUBSTRING(created_at,1,10) FROM orders (1~10번째 자리 까지 자르기)

 

케이스 문법

경우에 따라 원하는 값을 새필드에 출력

SELECT pu.user_id, pu.POINT,

(CASE WHEN pu.POINT>1000 THEN '잘 하고 있어요!'

ELSE ' 조금만 더 파이팅!' END) as msg

FROM point_users pu

 

통계 내기

with table1 as(

SELECT pu.user_id, pu.POINT,

(CASE WHEN pu.POINT > 10000 THEN '1만 이상'

WHEN pu.POINT > 5000 THEN '5천 이상'

ELSE '5천 미만' END) as lv

FROM point_users pu

)

 

SELECT a.lv, COUNT(*) as cnt from table1 a

group by a.lv

 

평균 이상의 포인트를 가지고 있으면 잘하고 있어요낮으면 열심히 합시다표시하기

SELECT pu.user_id,

pu.POINT,

(CASE WHEN pu.POINT > (select avg(point) from point_users) THEN '잘하고 있어요!'

else '조금만 더 화이팅' end) as msg

FROM point_users pu

 

이메일 도메인별 유저수 세어보기

SELECT domain, count(*) as cnt from(

SELECT SUBSTRING_INDEX(email,'@',-1) as domain from users

)a

group by domain

 

 

파이팅이 포함된 오늘의 다짐만 출력해보기 WHERE comment like '%화이팅%’

 

수강등록정보별 전체 강의 수와 들은 강의 수 출력해보기

SELECT a.enrolled_id, a.done_cnt, b.total_cnt from (

SELECT enrolled_id, count(*) as done_cnt from enrolleds_detail ed

WHERE done=1

group by enrolled_id

)a

inner join(

SELECT enrolled_id, count(*) as total_cnt from enrolleds_detail ed

group by enrolled_id

)b on a.enrolled_id = b.enrolled_id

 

위와 아래 동일

 

with table1 as (

SELECT enrolled_id, count(*) as done_cnt from enrolleds_detail ed

WHERE done=1

group by enrolled_id

),table2 as (

SELECT enrolled_id, count(*) as total_cnt from enrolleds_detail ed

group by enrolled_id

)

 

SELECT a.enrolled_id,

a.done_cnt,

b.total_cnt

from table1 a

inner join table2 b on a.enrolled_id = b.enrolled_id

 

수강등록정보별 전체 강의 수와 들은 강의 수 출력해보기+비율 넣기

with table1 as (

SELECT enrolled_id, count(*) as done_cnt from enrolleds_detail ed

WHERE done=1

group by enrolled_id

),table2 as (

SELECT enrolled_id, count(*) as total_cnt from enrolleds_detail ed

group by enrolled_id

)

  

SELECT a.enrolled_id,

a.done_cnt,

b.total_cnt,

round((a.done_cnt/b.total_cnt),2) as ratio

from table1 a

inner join table2 b on a.enrolled_id = b.enrolled_id