Database/SQL

[MySQL] [์ŠคํŒŒ๋ฅดํƒ€์ฝ”๋”ฉํด๋Ÿฝ SQL] Subquery, With, ๋ฌธ์ž์—ด, Case

Ella_K 2022. 7. 16. 23:48

๐Ÿ”ฅ Subquery๋ž€?

  • ์ฟผ๋ฆฌ ์•ˆ์˜ ์ฟผ๋ฆฌ
  • ํ•˜์œ„ ์ฟผ๋ฆฌ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์œ„ ์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ž์ฃผ ์“ฐ์ด๋Š” Subqueary ์œ ํ˜•: Where์— ๋“ค์–ด๊ฐ€๋Š” Subquery, Select์— ๋“ค์–ด๊ฐ€๋Š” Subquery, From์— ๋“ค์–ด๊ฐ€๋Š” Subquery
  • () ์•ˆ์— subquery๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค.

 


๐Ÿ”ฅ Where ์ ˆ์— ๋“ค์–ด๊ฐ€๋Š” Subquery

Subquery์˜ ๊ฒฐ๊ณผ๋ฅผ ์กฐ๊ฑด์— ํ™œ์šฉํ•œ๋‹ค.

where ํ•„๋“œ๋ช… in (subquery)

 

์‚ฌ์šฉ ์˜ˆ์‹œ

  • ์นด์นด์˜ค ํŽ˜์ด๋กœ ๊ฒฐ์ œํ•œ ์ฃผ๋ฌธ๊ฑด ์œ ์ €๋“ค๋งŒ ์œ ์ € ํ…Œ์ด๋ธ”์—์„œ ์ถ”์ถœ
select * from users u
where u.user_id in (select o.user_id from orders o 
                    where o.payment_method = 'kakaopay');
โ€ป ์ฟผ๋ฆฌ ์‹คํ–‰ ์ˆœ์„œ: from → where์ ˆ ์•ˆ subquery → where → select 
1. from users u : users์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜จ๋‹ค.
2. (select o.user_id from orders o
     where o.payment_method = 'kakakopay') : ์นด์นด์˜ค ํŽ˜์ด๋กœ ๊ฒฐ์ œํ•œ user_id ๋ช…๋‹จ์„ ๋ฝ‘๋Š”๋‹ค. 
3. where u.user_id in () : subquery์˜ ๊ฒฐ๊ณผ์— ํ•ด๋‹น๋˜๋Š” 'user_id์˜ ๋ช…๋‹จ' ์กฐ๊ฑด์œผ๋กœ ํ•„ํ„ฐ๋ง ํ•œ๋‹ค.
4. select * : ์กฐ๊ฑด์— ๋งž๋Š” users ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ

 

  • ์ด์”จ ์„ฑ์„ ๊ฐ€์ง„ ์œ ์ €๋“ค์˜ ํ‰๊ท  ํฌ์ธํŠธ๋ณด๋‹ค ๋” ๋งŽ์€ ํฌ์ธํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์ถ”์ถœ
select * from point_users pu
where pu.point > (
	select round(avg(pu2.point)) from point_users pu2
	where pu2.user_id in 
	(
		select u.user_id from users u
		where u.name = '์ด**'
	)
)
subquery์•ˆ์— subquery๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

 

select * from point_users pu 
where pu.point > 
	(select avg(pu2.point) from point_users pu2
	inner join users u 
	on pu2.user_id = u.user_id 
	where u.name = "์ด**");
subquery ํ•ด์„:
point ์ •๋ณด๋Š” point_usersํ…Œ์ด๋ธ” ์•ˆ์— ์žˆ๊ณ , name ์ •๋ณด๋Š” users ํ…Œ์ด๋ธ” ์•ˆ์— ์žˆ์œผ๋ฏ€๋กœ, ๋‘ ํ…Œ์ด๋ธ”์„ ํ•ฉ์นœ๋‹ค.
๊ทธ ํ›„ ํ•ฉ์นœ ํ…Œ์ด๋ธ”์—์„œ ์„ฑ์ด ์ด์”จ์ธ ๋ฐ์ดํ„ฐ๋“ค๋งŒ ์ถ”์ถœํ•˜๋„๋ก ์กฐ๊ฑด์„ ๊ฑธ๊ณ , ๊ทธ ๋ฐ์ดํ„ฐ์˜ point ํ‰๊ท ์„ ๊ตฌํ•œ๋‹ค.

 


๐Ÿ”ฅ Select ์ ˆ์— ๋“ค์–ด๊ฐ€๋Š” Subquery

Select๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ๋ถ€๋ถ„.

๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•  ๋•Œ, ๊ธฐ์กด ํ…Œ์ด๋ธ”์— ํ•จ๊ป˜ ๋ณด๊ณ  ์‹ถ์€ ํ†ต๊ณ„ ๋ฐ์ดํ„ฐ๋ฅผ Subquery๋ฅผ ์ด์šฉํ•ด ๋ถ™์ธ๋‹ค.

select ํ•„๋“œ๋ช…, ํ•„๋“œ๋ช…, (subquery) from ...

select * from ๋ฌธ์—์„œ ๋ฐ์ดํ„ฐ๋Š” ํ•œ์ค„ ํ•œ์ค„ ์ถœ๋ ฅํ•œ๋‹ค. select ์•ˆ์˜ Subquery๋Š” ๋งค ๋ฐ์ดํ„ฐ ํ•œ์ค„๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค.

 

์‚ฌ์šฉ ์˜ˆ์‹œ

  • '์˜ค๋Š˜์˜ ๋‹ค์ง'(chekins) ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ณ  ์‹ถ์€๋ฐ, course_id๊ฐ€ ๋ฐ›์•˜๋˜ ์ข‹์•„์š” ์ˆ˜ ํ‰๊ท ์„ checkins ํ…Œ์ด๋ธ” course_id๋งˆ๋‹ค ๋ถ™์ธ๋‹ค.
select 
	checkin_id, 
	course_id, 
	user_id, 
	likes,
	(
	select round(avg(c2.likes),1) from checkins c2
	where c.course_id = c2.course_id 
	) as course_avg
  from checkins c
1. select * from ๋ฌธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ์ค„ ํ•œ์ค„ ์ถœ๋ ฅํ•˜๋Š” ๊ณผ์ •์—์„œ
2. select ์•ˆ์˜ subquery๊ฐ€ ๋งค ๋ฐ์ดํ„ฐ ํ•œ์ค„๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค.
3. ๊ทธ ๋ฐ์ดํ„ฐ ํ•œ ์ค„์˜ course_id๋ฅผ ๊ฐ–๋Š” ๋ฐ์ดํ„ฐ์˜ ํ‰๊ท  ์ข‹์•„์š” ๊ฐ’์„ subquery์—์„œ ๊ณ„์‚ฐํ•ด์„œ
4. ํ•จ๊ป˜ ์ถœ๋ ฅํ•œ๋‹ค.

 


๐Ÿ”ฅ From ์ ˆ์— ๋“ค์–ด๊ฐ€๋Š” Subquery

์—ฌ๋Ÿฌ table์—์„œ selectํ•˜๊ณ  ์‹ถ์„ ๋•Œ from์ ˆ์— subquery๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

1. selectํ•˜๊ณ  ์‹ถ์€ ์ •๋ณด๊ฐ€ ๋“ค์–ด ์žˆ๋Š” ํ…Œ์ด๋ธ”๋“ค์—์„œ, ๊ฐ์ž select๋ฅผ ์ˆ˜ํ–‰ํ•ด ์ƒˆ๋กœ์šด ํ…Œ์ด๋ธ”์ด ๋œ๋‹ค.

2. subquery๋ฅผ ์ด์šฉํ•ด ์›ํ•˜๋Š” ์ •๋ณด๋“ค์ด ์žˆ๋Š”(select๊ฐ€ ์ˆ˜ํ–‰๋œ) ํ…Œ์ด๋ธ”๋“ค์„ join ํ•œ๋‹ค.

(๋‚˜์ค‘์— selectํ•  ๋•Œ๋ฅผ ์œ„ํ•ด ๋ณ„์นญ์„ ์‚ฌ์šฉํ•œ๋‹ค.)

3. join๋œ ๊ฐ ํ…Œ์ด๋ธ”์˜ ๋ณ„์นญ์„ ์ด์šฉํ•ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋“ค์„ selectํ•œ๋‹ค.

 

์‚ฌ์šฉ ์˜ˆ์‹œ

์ถ”์ถœํ•˜๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ: course title, course๋ณ„ ์œ ์ €์˜ ์ฒดํฌ์ธ ๊ฐœ์ˆ˜, course๋ณ„ ์ธ์›, ํผ์„ผํŠธ

1. course_id๋ณ„ ์œ ์ €์˜ ์ฒดํฌ์ธ ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•œ๋‹ค.

select course_id, count(distinct(user_id)) as cnt_checkins from checkins
group by course_id

 

2. course_id๋ณ„ ์ธ์›์„ ๊ตฌํ•œ๋‹ค.

select course_id, count(*) as cnt_total from orders
group by course_id

 

3. 1,2๋ฒˆ๊ณผ course์˜ title ์ •๋ณด๊ฐ€ ์žˆ๋Š” coursesํ…Œ์ด๋ธ”์„ joinํ•œ๋‹ค.

select *
       from
		(
			select course_id, count(distinct(user_id)) as cnt_checkins 
			from checkins
			group by course_id 
		) a
		inner join (
			select course_title, 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

 

4. join๋œ ๊ฐ ํ…Œ์ด๋ธ”์˜ ๋ณ„์นญ์„ ์ด์šฉํ•ด select ํ•˜๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๋“ค์„ select ํ•œ๋‹ค.

select c.title, 
       a.cnt_checkins, 
       b.cnt_total,
       round(a.cnt_checkins/b.cnt_total,4) as ratio
       from
		(
			select course_id, count(distinct(user_id)) as cnt_checkins 
			from checkins
			group by course_id 
		) a
		inner join (
			select course_title, 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 ์ ˆ์„ ์ด์šฉํ•ด subquery๋ฅผ ๊ฐ€์ƒ ํ…Œ์ด๋ธ”๋ช…์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

with table1 as (subquery1), table2 as (subquery2) ....

 

์‚ฌ์šฉ ์˜ˆ์‹œ

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
SQL์€ ์ค„๋กœ ๋„์–ด์ ธ์žˆ์œผ๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์ฟผ๋ฆฌ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ๋งˆ์ง€๋ง‰ ์ฟผ๋ฆฌ๋ฌธ์„ ์‹คํ–‰ํ•œ๋‹ค.
ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฌธ์€ ์ค„ ๋„์–ด์“ฐ๊ธฐ ์—†์ด ์ž‘์„ฑํ•˜์ž

๋˜๋Š” ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์€ ์ฟผ๋ฆฌ๋ฌธ์„ ๋“œ๋ž˜๊ทธํ•ด์„œ ์‹คํ–‰ํ•ด๋„ ๋œ๋‹ค! 

 


๐Ÿ”ฅ ๋ฌธ์ž์—ด

๋ฌธ์ž์—ด ์ชผ๊ฐœ๊ธฐ

SUBSTRING_INDEX(๋ฌธ์ž์—ด, ์ชผ๊ฐœ๊ณ  ์‹ถ์€ ๊ธฐ์ค€ ๋ฌธ์ž์—ด, ๊ฐ€์ง€๊ณ  ์˜ฌ ๋ฌธ์ž์—ด ์œ„์น˜)

 

  • ์ด๋ฉ”์ผ์—์„œ ์•„์ด๋””๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ
select user_id, email, SUBSTRING_INDEX(email, '@', 1) from users

 

  • ์ด๋ฉ”์ผ์—์„œ ๋„๋ฉ”์ธ๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ
select user_id, email, SUBSTRING_INDEX(email, '@', -1) from users

 

๋ฌธ์ž์—ด ์ผ๋ถ€๋งŒ ์ถœ๋ ฅ

substring(๋ฌธ์ž์—ด, ๊ฐ€์ ธ์˜ฌ ๋ฌธ์ž์—ด ์ฒซ ๊ธ€์ž ์œ„์น˜, ๋ช‡๊ฐœ์˜ ๊ธ€์ž๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ์‹ถ์€์ง€)

 

  • ordersํ…Œ์ด๋ธ”์—์„œ ๋‚ ์งœ๊นŒ์ง€ ์ถœ๋ ฅํ•˜๊ธฐ
select order_no, created_at, substring(created_at,1,10) as date from orders

 


๐Ÿ”ฅ Case

๊ฒฝ์šฐ(case)์— ๋”ฐ๋ผ ์›ํ•˜๋Š” ๊ฐ’์„ ์ƒˆ ํ•„๋“œ์— ์ถœ๋ ฅํ•ด๋ณด๊ธฐ

select ํ•„๋“œ๋ช…, ํ•„๋“œ๋ช…,
case
when ์กฐ๊ฑด1 then ์ถœ๋ ฅ๊ฐ’1
when ์กฐ๊ฑด2 then ์ถœ๋ ฅ๊ฐ’2
.
.
.
else ์กฐ๊ฑดn ์ถœ๋ ฅ๊ฐ’n
end as ๋ณ„์นญ
from ํ…Œ์ด๋ธ”๋ช…

 

์‚ฌ์šฉ์˜ˆ์‹œ

  • point_usersํ…Œ์ด๋ธ”์—์„œ 10000์ ๋ณด๋‹ค ๋†’์€ ํฌ์ธํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด '์ž˜ํ•˜๊ณ  ์žˆ์–ด์š”!', ํ‰๊ท ๋ณด๋‹ค ๋‚ฎ์œผ๋ฉด 'ํž˜๋‚ด์š”!' ๋ผ๊ณ  ํ‘œ์‹œํ•˜๊ณ , ์ด ์ƒˆ๋กœ์šด ํ•„๋“œ๋ช…์€ '๊ตฌ๋ถ„'์ด๋‹ค.
select pu.point_user_id, pu.point,
case 
when pu.point > 10000 then '์ž˜ ํ•˜๊ณ  ์žˆ์–ด์š”!'
else 'ํž˜๋‚ด์š”!'
END as '๊ตฌ๋ถ„'
from point_users pu;

 

  • point_users ํ…Œ์ด๋ธ”์—์„œ ํฌ์ธํŠธ๊ฐ€ 5์ฒœ ๋ฏธ๋งŒ, 5์ฒœ ์ด์ƒ, 1๋งŒ ์ด์ƒ์ธ user๋“ค์˜ ์ˆ˜ ํ†ต๊ณ„๋‚ด๊ธฐ
with table1 as (
	select pu.point_user_id, pu.point,
	case 
	when pu.point > 10000 then '1๋งŒ ์ด์ƒ'
	when pu.point > 5000 then '5์ฒœ ์ด์ƒ'
	else '5์ฒœ ๋ฏธ๋งŒ'
	END as level
	from point_users pu
)
select level, count(*) as cnt from table1
group by level

 


Source

์ŠคํŒŒ๋ฅดํƒ€ ์ฝ”๋”ฉํด๋Ÿฝ ๋‚ด์ผ๋ฐฐ์›€๋‹จ ์—‘์…€๋ณด๋‹จ ์‰ฌ์šด SQL 4์ฃผ์ฐจ