내일배움캠프/내일배움단
내일배움단 -개발일지 2주차 (2)
sogummi
2023. 3. 8. 23:48
9일차
-오늘 계획 : SQL 1~3주 문제 복습 풀기(완료), SQl 공부
01.Subquery
: 하나의 SQL 쿼리 안에 또다른 SQL쿼리가 있는 것
where, select, from 절에서 유용하게 사용
Ex-1) kakaopay로 결제한 유저들의 정보 보기
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'
inner join을 사용한 쿼리를 Subquery로 표현
select u.user_id, u.name, u.email from users u
where u.user_id in (
select user_id from orders
where payment_method = 'kakaopay'
)
=>
우선 서브쿼리 안의 kakaopay로 결제한 user_id를 모두 구하고
그 후, user_id가 서브쿼리안에 속한 유저만 골라보도록 함
1-1) Where 필드명 in (subquery)
Subquery의 결과를 조건에 활용하는 방식으로 유용
포인트가 평균보다 많은 사람들의 데이터를 추출
select * from point_users pu
where point > (
SELECT avg(point) from point_users pu
)
-> 굳이 평균값을 적지 않고 Subquery를 넣는 이유?
평균값이 변할 수 있기 때문
1-2) Select 필드명, 필드명, (subquery) from .. .
=> Select는 결과를 출력해줌, 기존 테이블에 함께 보고싶은 통계 데이터를 손쉽게 붙이는 것에 사용
Ex)
select c.checkin_id, c.user_id, c.likes,
(select avg(likes) from checkins c2
where c2.user_id = c.user_id) as avg_like_user
from checkins c;
(1) 밖의 select * from 문에서 데이터를 한줄한줄 출력하는 과정에서
(2) select 안의 subquery가 매 데이터 한줄마다 실행되는데
(3) 그 데이터 한 줄의 user_id를 갖는 데이터의 평균 좋아요 값을 subquery에서 계산해서
(4) 함께 출력
// 직접 해보는 게 이해에 빠름
** Select Subquery 복습 필수 문제!
문제)
checkins 테이블에 course_id별 평균 likes수 필드 우측에 붙여보기
오답)
select checkin_id, course_id, user_id, likes,
(select avg(c.likes) from checkins c
where c.course_id = course_id)
from checkins
해답)
select checkin_id, course_id, user_id, likes,
(select avg(c.likes) from checkins c
where c.course_id = c2.course_id)
from checkins c2
// subquery안의 course_id와 main query의 course_id를 join시켜야 하므로 alias를 꼭 붙여줘야 한다 ! alias를 쓰는 이유,, 일종의 변수 개념이기 때문에 ! + 구분 짓기 위해서
10일차
1-3) From에 들어가는 Subquery (가장 많이 사용)
보통 내가 만든 select와 이미 있는 테이블을 join하고 싶을 때 사용
Ex)
select c.title, b.cnt_checkins, a.cnt_total, (b.cnt_checkins/a.cnt_total) as ratio
from
(
select course_id, count(*) as cnt_total from orders
group by course_id
) a
inner join (
select course_id, count(distinct(user_id)) as cnt_checkins from checkins
group by course_id
) b on a.course_id = b.course_id
inner join courses c
on a.course_id = c.course_id
02.with 구문
- from안에 들어가는 subquery를 쓸 때 훨씬 간결하게 표현할 수 있다.
Ex)
with table1 as (
select course_id, count(*) as cnt_total from orders
group by course_id
), table2 as (
select course_id, count(distinct(user_id)) as cnt_checkins from checkins
group by course_id
)
select c.title,
b.cnt_checkins,
a.cnt_total,
(b.cnt_checkins/a.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
-> 이처럼 from과 inner join에 들어가는 subquery를 with구문으로 빼서 각각의 임시 테이블을 만들어주었다. *with구문을 사용할 때는 항상 윗단에다가 적도록 해야한다.
- 문자열 데이터 가공실무에서는 문자열을 원하는 형태로 가공해야하는 경우가 많다! 그렇다면?
1-1) SUBSTRING_INDEX ; 문자열 쪼개기
문자열을 한 기준에서 기준의 앞 데이터나 뒤의 데이터만 쪼개는 것
예시 1) SUBSTRING_INDEX(email,'@',1)
@기준으로 문자열을 쪼개고, 첫 번째 조각을 가져온다 (아이디)
2) SUBSTRING_INDEX(email,'@',-1)
@기준으로 문자열을 쪼개고, 마지막 조각을 가져온다 (도메인)
1-2) SUBSTRING ; 문자열 일부 출력
SUBSTRING(칼럼명, 출력시작위치, 마지막위치)
ex) 칼럼(created_at) [2023-02-16 20:29:04] 기준
SELECT order_no, SUBSTRING(created_at,1,10) as date from orders
=> 일자 출력
SELECT order_no, SUBSTRING(created_at,12,8) as date from orders
=> 시간 출력
결과를 group by로 통계를 내도록 활용 가능
- case when 조건문
SELECT pu.user_id, pu.point,
(case when pu.point > 10000 then '잘 하고 있어요!'
else '조금만 더 파이팅!' end) as msg
from point_users pu
=> 유저의 포인트가 10000보다 많거나 적을 경우에 따른 메세지 조건
+) subquery와 case when
SELECT a.lv, count(*) FROM (
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
) a
group by a.lv
=> subquery로 조건문을 통계 낼 수 있다
++) with절로 표현
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(*) FROM table1 a
group by a.lv
[퀴즈] 수강등록정보(enrolled_id)별 전체 강의 수와 들은 강의의 수, 그리고 진도율 출력해보기
답1) 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 cnt from enrolleds_detail ed
group by enrolled_id
)
select a.enrolled_id,
a.done_cnt,
b.cnt,
round((a.done_cnt/b.cnt),2) as ratio
from table1 a
inner join table2 b on a.enrolled_id = b.enrolled_id
답2) select enrolled_id,
sum(done) as cnt_done,
count(*) as totla_cnt,
round((sum(done)/count(*)),2) as ratio
from enrolleds_detail ed
group by enrolled_id