๐ŸŒธSQL - ์ด์ •๋ฆฌ๐ŸŒธ

Leehyunยท2025๋…„ 2์›” 25์ผ
1

๋‚ด์ผ๋ฐฐ์›€์บ ํ”„

๋ชฉ๋ก ๋ณด๊ธฐ
6/14
post-thumbnail

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ SQL

๐Ÿซต๐Ÿป ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค : ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ํฐ ํด๋”
SQL : SQL์€ '์ฝ”๋“œ'๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์š”์ฒญ์„ ํ•˜๊ธฐ ์œ„ํ•œ '์–ธ์–ด'

SQL ์ด์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์š”์ฒญํ•˜๋Š” ์งˆ์˜๋ฅผ QUERY๋ผ๊ณ  ํ•จ


๋ฐ์ดํ„ฐ ์กฐํšŒ

  • SELECT : ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ธฐ๋ณธ ๋ช…๋ น์–ด
  • FROM : ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ํ…Œ์ด๋ธ”์„ ํŠน์ •ํ•ด์ฃผ๋Š” ๋ฌธ๋ฒ•
  • '*' : ๋ชจ๋“  ์ปฌ๋Ÿผ์„ ๊ฐ€์ ธ์™€์ค€๋‹ค๋Š” ์˜๋ฏธ

์ปฌ๋Ÿผ ๋ช… ๋ฐ”๊พธ๊ธฐ (๋ณ„๋ช…์ฃผ๊ธฐ)

  • ๋ฐฉ๋ฒ• 1 : ์ปฌ๋Ÿผ1 as ๋ณ„๋ช…1
  • ๋ฐฉ๋ฒ• 2 : ์ปฌ๋Ÿผ2 ๋ณ„๋ช…2

    ๐ŸŒธ ์˜๋ฌธ, ์–ธ๋”๋ฐ”๋Š” ๋ณ„๋ช…๋งŒ ์ ์–ด๋„ ๋˜์ง€๋งŒ, ํŠน์ˆ˜๋ฌธ์ž ๋ฐ ํ•œ๊ธ€์€ ํฐ ๋”ฐ์˜ดํ‘œ ์•ˆ์— ๋ณ„๋ช… ๊ธฐ์žฌํ•ด์•ผํ•จ ๐ŸŒธ


์กฐ๊ฑด์— ๋งž๊ฒŒ ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋ง

  • WHERE : ํ•„ํ„ฐ๋ง ์กฐ๊ฑด ์ œ์‹œ
  • ๋น„๊ต ์—ฐ์‚ฐ ( = , <>, >, >=, < , <=)
  • BETWEEN : A ์ด์ƒ B ์ดํ•˜
  • IN : ํฌํ•จํ•˜๋Š” ์กฐ๊ฑด
  • LIKE : ์™„์ „ํžˆ ๋˜‘๊ฐ™์ง€๋Š” ์•Š์ง€๋งŒ, ๋น„์Šทํ•œ ๊ฐ’ ์กฐ๊ฑด์œผ๋กœ ์ฃผ๊ธฐ

๐Ÿ€ IF ) ์กฐ๊ฑด์ด ์—ฌ๋Ÿฌ ๊ฐœ? -> ๋…ผ๋ฆฌ์—ฐ์‚ฐ(and, or, not)์œผ๋กœ ์—ฐ๊ฒฐ์‹œํ‚ค๊ธฐ!


์—‘์…€ ๋Œ€์‹  SQL๋กœ ํ•œ๋ฒˆ์— ๊ณ„์‚ฐํ•˜๊ธฐ

  • ์ˆซ์ž ์—ฐ์‚ฐ (๋ง์…ˆ+, ๋บ„์…ˆ-, ๊ณฑ์…ˆ*, ๋‚˜๋ˆ—์…ˆ / ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
  • ํ•ฉ๊ณ„ : SUM
  • ํ‰๊ท  : AVG
  • ํ–‰ ๊ฐœ์ˆ˜ ์„ธ๊ธฐ : COUNT(์ปฌ๋Ÿผ) (์ปฌ๋Ÿผ๋ช… ๋Œ€์‹  1, * ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
  • ์ตœ๋Œ“๊ฐ’ : MAX
  • ์ตœ์†Ÿ๊ฐ’ : MIN

    ๐Ÿ‘… IF ) ๋ฒ”์ฃผ ๋ณ„๋กœ ๊ณ„์‚ฐํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด? -> GROUP BY ์ด์šฉ!
    COUNT๋Š” ์œ ์˜๋ฏธํ•œ ๊ณ„์‚ฐ์œผ๋กœ ์ด์šฉํ• ๋ ค๋ฉด GROUP BY ํ•„์ˆ˜์ ์œผ๋กœ ํ•„์š”ํ•จ!


QUERY ๊ฒฐ๊ณผ ์ •๋ ฌํ•˜๊ธฐ

  • ์˜ค๋ฆ„์ฐจ์ˆœ : ORDER BY ์ปฌ๋Ÿผ๋ช… ASC (ORDER BY์˜ ๊ธฐ๋ณธํ˜•์ด ์˜ค๋ฆ„์ฐจ์ˆœ์ด๋ผ ASC ์ƒ๋žต ๊ฐ€๋Šฅ)
  • ๋‚ด๋ฆผ์ฐจ์ˆœ : ORDER BY ์ปฌ๋Ÿผ๋ช… DESC

SQL ์ž‘์„ฑ ์ˆœ์„œ

select 
from 
where 
group by  
having 
order by

โœ‹๐Ÿป HAVING์€ ๊ทธ๋ฃน ๋ณ„๋กœ ์—ฐ์‚ฐํ•œ ๋‹ค์Œ ์กฐ๊ฑด์„ ์ฃผ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ


๋ฐ์ดํ„ฐ ๊ฐ€๊ณต

  • REPLACE(๋ฐ”๊ฟ€ ์ปฌ๋Ÿผ, ํ˜„์žฌ ๊ฐ’, ๋ฐ”๊ฟ€ ๊ฐ’) : ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๋ฐ”๊พธ์–ด ๋ฒ„๋ฆฌ๊ธฐ
  • SUBSTRING(์กฐํšŒ ํ•  ์ปฌ๋Ÿผ, ์‹œ์ž‘ ์œ„์น˜, ๊ธ€์ž ์ˆ˜) : ์›ํ•˜๋Š” ๋ฌธ์ž๋งŒ ๋‚จ๊ธฐ๊ณ  ์ž๋ฅด๊ธฐ
  • CONCAT(๋ถ™์ด๊ณ  ์‹ถ์€ ๊ฐ’1, ๋ถ™์ด๊ณ  ์‹ถ์€ ๊ฐ’2, ๋ถ™์ด๊ณ  ์‹ถ์€ ๊ฐ’3) : ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์˜ ๋ฌธ์ž ํ•ฉ์น˜๊ธฐ

์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์—ฐ์‚ฐ ํ•˜๋Š”๋ฒ•

  • if(์กฐ๊ฑด, ์กฐ๊ฑด์„ ์ถฉ์กฑํ•  ๋•Œ, ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜์ง€ ์•Š์„ ๋•Œ) : ๋‹จ์ผ ์กฐ๊ฑด์„ ์ง€์ •ํ•  ๋•Œ
  • case when ์กฐ๊ฑด1 then ๊ฐ’(์ˆ˜์‹)1
    when ์กฐ๊ฑด2 then ๊ฐ’(์ˆ˜์‹)2
    else ๊ฐ’(์ˆ˜์‹)3
    end
    : ๋‘๊ฐœ ์ด์ƒ์˜ ์กฐ๊ฑด์„ ์ง€์ •ํ•  ๋•Œ

DATA TYPE ์˜ค๋ฅ˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

๐Ÿ‘‹๐Ÿป cast ํ•จ์ˆ˜ ์ด์šฉ

// ์ˆซ์ž๋กœ ๋ณ€๊ฒฝ
cast(if(rating = 'Not given', '1', rating) as decimal)

// ๋ฌธ์ž๋กœ ๋ณ€๊ฒฝ
concat(restaurant_name, '-', cast(order_id as char))

SUBQUERY

๐Ÿคญ QUERY ์•ˆ์— QUERY
์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•ด์•ผํ•  ๋•Œ
์กฐ๊ฑด๋ฌธ์— ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ
์กฐ๊ฑด์— QUERY ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ
์‚ฌ์šฉํ•˜๋ฉด ์œ ์šฉํ•จ

์ž‘๋™ ์ˆœ์„œ : ์•ˆ์ชฝ ์ฟผ๋ฆฌ -> ๋ฐ”๊นฅ์ชฝ ์ฟผ๋ฆฌ

SUBQUERY ์ข…๋ฅ˜
- ์ค‘์ฒฉ(์ผ๋ฐ˜) ์„œ๋ธŒ์ฟผ๋ฆฌ - WHERE ์ ˆ์—์„œ ์‚ฌ์šฉ
- ์Šค์นผ๋ผ ์„œ๋ธŒ์ฟผ๋ฆฌ - SELECT ์ ˆ์—์„œ ์‚ฌ์šฉ, ํ•˜๋‚˜์˜ ์ปฌ๋Ÿผ์ฒ˜๋Ÿผ ์‚ฌ์šฉ
- ์ธ๋ผ์ธ ๋ทฐ(๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ) - FROM ์ ˆ์—์„œ ์‚ฌ์šฉ, ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์ฒ˜๋Ÿผ ์‚ฌ์šฉ, ๋ช…์นญ์„ ๋ฐ˜๋“œ์‹œ ๊ธฐ์žฌ


์„œ๋กœ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ” ๋ถ™์ด๊ธฐ(UNION, JOIN)

  • UNION ํ•จ์ˆ˜ : ํ…Œ์ด๋ธ” ์ˆ˜์ง๊ฒฐํ•ฉ
    <๊ธฐ๋ณธ ๊ตฌ์กฐ>

    # union/union all ๊ธฐ๋ณธ๊ตฌ์กฐ
    # ์ปฌ๋Ÿผ ์ˆœ์„œ๊ฐ€ ๊ฐ™๊ณ , ๊ทธ ํ˜•์‹์ด ๊ฐ™์•„์•ผ ํ•จ
    select ์ปฌ๋Ÿผ1, ์ปฌ๋Ÿผ2, ์ปฌ๋Ÿผ3.. 
    from ํ…Œ์ด๋ธ”๋ช…1
    union (all) #์ˆ˜์ง๊ฒฐํ•ฉ ๋ช…์‹œ
    select ์ปฌ๋Ÿผ1, ์ปฌ๋Ÿผ2, ์ปฌ๋Ÿผ3..
    from ํ…Œ์ด๋ธ”๋ช…2 

  • JOIN : ํ…Œ์ด๋ธ” ์ˆ˜ํ‰๊ฒฐํ•ฉ

  • SELECT *
    FROM ํ…Œ์ด๋ธ”1 a LEFT JOIN ํ…Œ์ด๋ธ”2 b ON a.๊ณตํ†ต ์ปฌ๋Ÿผ = b.๊ณตํ†ต ์ปฌ๋Ÿผ
    -> ๊ณตํ†ต ์ปฌ๋Ÿผ์„ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์— ๊ฐ’์ด ์—†๋”๋ผ๋„ ๋ชจ๋‘ ์กฐํšŒ

  • SELECT *
    FROM ํ…Œ์ด๋ธ”1 a INNER JOIN ํ…Œ์ด๋ธ”2 b ON a.๊ณตํ†ต ์ปฌ๋Ÿผ = b.๊ณตํ†ต ์ปฌ๋Ÿผ
    -> ๊ณตํ†ต ์ปฌ๋Ÿผ์„ ๊ธฐ์ค€์œผ๋กœ ๋‘ ํ…Œ์ด๋ธ” ๋ชจ๋‘์— ์žˆ๋Š” ๊ฐ’๋งŒ ์กฐํšŒ

    ๐Ÿซก ๊ณตํ†ต ์ปฌ๋Ÿผ์€ '๊ณตํ†ต ๊ฐ’'์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ๋ช…์€ ๋‹ฌ๋ผ๋„ ๊ดœ์ฐฎ์Œ!
    ๊ณตํ†ต์ปฌ๋Ÿผ์ด ์—†๋‹ค๋ฉด, ์กฐ์ธ์„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์„ ๊ธฐ์–ต!
    ๊ณตํ†ต์ปฌ๋Ÿผ์€ ๊ผญ ํ•˜๋‚˜๊ฐ€ ์•„๋‹ ์ˆ˜ ์žˆ์Œ -> ์—ฌ๋Ÿฌ ๊ฐœ๋„ ๊ฐ€๋Šฅ

    ์•„๋ž˜ ERD, MAPPING CARDINALITY๋กœ ํ™•์ธ


ERD & Mapping Cardinality



๊ฒฐ์ธก๊ฐ’ ์ฒ˜๋ฆฌํ•˜๊ธฐ

  • ์—†๋Š” ๊ฐ’ ์ œ์™ธํ•ด์ฃผ๊ธฐ
    if (rating<> 'Not given', rating, null)
  • ๋‹ค๋ฅธ ๊ฐ’ ๋Œ€์‹  ์‚ฌ์šฉํ•˜๊ธฐ
    1) ๋‹ค๋ฅธ ๊ฐ’์ด ์žˆ์„ ๋•Œ ์กฐ๊ฑด๋ฌธ ์ด์šฉ -> if (rating<> 'Not given', rating, ๋Œ€์ฒด๊ฐ’)
    2) null ๊ฐ’์ผ ๋•Œ -> coalesce(age, ๋Œ€์ฒด๊ฐ’)

์ด์ƒ์น˜ ์ฒ˜๋ฆฌํ•˜๊ธฐ

like 2์„ธ, 150์„ธ
-> ์กฐ๊ฑด๋ฌธ์œผ๋กœ ์ƒ์‹์ ์ธ ์ˆ˜์ค€์•ˆ์—์„œ ๋ฒ”์œ„๋กœ ์ง€์ •ํ•ด๋ฒ„๋ฆฌ๊ธฐ


PIVOT TABLE

  • PIVOT TABLE : 2๊ฐœ ์ด์ƒ์˜ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘๊ณ„ํ•  ๋•Œ, ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ๋ฐฐ์—ดํ•˜๋Š” ๊ฒƒ
    <์˜ˆ์‹œ>
    ์Œ์‹์ ๋ณ„, ์‹œ๊ฐ„๋ณ„, ์ฃผ๋ฌธ๊ฑด ์ˆ˜ PIVOT TABLE ๋งŒ๋“ค๊ธฐ
    ์—ฌ๊ธฐ์„œ maxํ•จ์ˆ˜๋Š” ์ผ๋‹จ ์ดํ•ดํ•˜์ง€ ๋ง๊ณ  PIVOT TABLE ์“ธ ๋•Œ ์ด์šฉํ•˜์ž
select restaurant_name,
       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 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
) a
group by 1
order by 7 desc

WINDOW FUCTION

  • ๊ธฐ๋ณธ ๊ตฌ์กฐ
    window_function(argument) over (partition by ๊ทธ๋ฃน ๊ธฐ์ค€ ์ปฌ๋Ÿผ order by ์ •๋ ฌ ๊ธฐ์ค€)

    ๐Ÿซฅ window_function๊ณผ over์€ ์ง๊ฟ!

<RANK ํ•จ์ˆ˜ ์˜ˆ์‹œ>
์Œ์‹ ํƒ€์ž…๋ณ„๋กœ ์ฃผ๋ฌธ ๊ฑด์ˆ˜๊ฐ€ ๊ฐ€์žฅ ๋งŽ์€ ์ƒ์  3๊ฐœ์”ฉ ์กฐํšŒํ•˜๊ธฐ

select cuisine_type,
       restaurant_name,
       order_count,
       rn "์ˆœ์œ„"
from
(
select cuisine_type,
       restaurant_name,
       rank() over (partition by cuisine_type order by order_count desc) rn,
       order_count
from
(
select cuisine_type, restaurant_name, count(1) order_count
from food_orders
group by 1, 2
) a
) b
where rn<=3
order by 1, 4

<SUM ํ•จ์ˆ˜ ์˜ˆ์‹œ>
๊ฐ ์Œ์‹์ ์˜ ์ฃผ๋ฌธ๊ฑด์ด ํ•ด๋‹น ์Œ์‹ ํƒ€์ž…์—์„œ ์ฐจ์ง€ํ•˜๋Š” ๋น„์œจ์„ ๊ตฌํ•˜๊ณ , ์ฃผ๋ฌธ๊ฑด์ด ๋‚ฎ์€ ์ˆœ์œผ๋กœ ์ •๋ ฌํ–ˆ์„ ๋•Œ ๋ˆ„์  ํ•ฉ ๊ตฌํ•˜๊ธฐ

select cuisine_type,
       restaurant_name,
       cnt_order,
       sum(cnt_order) over (partition by cuisine_type) sum_cuisine,
       sum(cnt_order) over (partition by cuisine_type order by cnt_order) cum_cuisine
from
(
select cuisine_type, 
	restaurant_name, 
	count(1) cnt_order
from food_orders
group by 1, 2
) a
order by cuisine_type , cnt_order

๋‚ ์งœ ํฌ๋งท & ์กฐ๊ฑด

  • yyyy-mm-dd ํ˜•์‹์˜ ์ปฌ๋Ÿผ์„ date type ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ
    -> date(์ปฌ๋Ÿผ๋ช…) ์‚ฌ์šฉ
  • date type์„ ๋…„, ์›”, ์ผ, ์ฃผ ๋กœ ์กฐํšŒํ•ด๋ณด๊ธฐ
    ->
date_format(date(date), '%Y') "๋…„", // ๋…„๋„ ์กฐํšŒ 
date_format(date(date), '%m') "์›”", // ์›” ์กฐํšŒ
date_format(date(date), '%d') "์ผ", // ์ผ ์กฐํšŒ
date_format(date(date), '%w') "์š”์ผ" // ์š”์ผ ์กฐํšŒ

REGEXP(์ •๊ทœ์‹)

  • REGEXP๋Š”ย LIKE๋ฅผ ์ด์šฉํ•œ ๊ฒ€์ƒ‰๊ณผ ๋‹ฌ๋ฆฌย Regular Expression(์ •๊ทœ ํ‘œํ˜„์‹)๋ฅผ ์ด์šฉํ•ด ๊ฒ€์ƒ‰ํ•จ
    -> REGEXP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด SQL์—์„œย ์ •๊ทœํ‘œํ˜„์‹์„ ํ™œ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ ์—ฐ์‚ฐ์ž๋ณด๋‹ค ๋ณต์žกํ•œ ๋ฌธ์ž์—ด ์กฐ๊ฑด์„ ๊ฑธ์–ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ


    ์ถœ์ฒ˜ : https://dadev.tistory.com/entry/MY-SQL-์ •๊ทœ์‹-REGEXP
profile
์งฑ๊ตฌ๊ฐ€ ์ฝ”๋”ฉ์„..?

0๊ฐœ์˜ ๋Œ“๊ธ€