ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๐Ÿ’ก ๋Œ€๊ทœ๋ชจ์˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์‹œ, ๊ฐ ๋ ˆ์ฝ”๋“œ ํ•˜๋‚˜ํ•˜๋‚˜๋ฅผ ๋‹ค๋ฃจ๊ธฐ๋Š” ์‰ฝ์ง€ ์•Š์Œ

๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘๊ณ„ํ•˜๊ณ  ๋ช‡๊ฐ€์ง€ ์ง€ํ‘œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ ์ „์ฒด์˜ ํŠน์ง• ํŒŒ์•…ํ•˜๊ธฐ!

 

- ๋ฐ์ดํ„ฐ ์ง‘์•ฝ : ํ‰๊ท , ์ตœ๋Œ€ ์ตœ์†Œ,,, ํ†ต๊ณ„ ์ง€ํ‘œ ์ถœ๋ ฅ → ์œˆ๋„ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ˆœ์„œ๋ฅผ ๊ณ ๋ คํ•˜๋Š” ์ฒ˜๋ฆฌ, ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์ฒ˜๋ฆฌ

- ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต : ํ…Œ์ด๋ธ” ํ˜•์‹์ด ์ง‘๊ณ„์— ์ ํ•ฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ํ…Œ์ด๋ธ”์„ ๊ฐ€๊ณตํ•ด์•ผ ํ•˜๋Š”์ง€!

 

1. ๊ทธ๋ฃน์˜ ํŠน์ง• ์žก๊ธฐ

์ง‘์•ฝ ํ•จ์ˆ˜ : ์—ฌ๋Ÿฌ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋‚˜์˜ ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜

ex) COUNT(), SUM()

์ƒํ’ˆ ํ‰๊ฐ€ ํ…Œ์ด๋ธ”

 

ํ…Œ์ด๋ธ” ์ „์ฒด์˜ ํŠน์ง•๋Ÿ‰ ๊ณ„์‚ฐํ•˜๊ธฐ

COUNT : ์ง€์ •ํ•œ ์ปฌ๋Ÿผ์˜ ๋ ˆ์ฝ”๋“œ ์ˆ˜ ๋ฆฌํ„ด

DISTINCT : ์ค‘๋ณต์„ ์ œ์™ธํ•˜๊ณ  ์ˆ˜๋ฅผ ์„ธ์›Œ์คŒ

SELECT
  COUNT(*) AS total_count
  , COUNT(DISTINCT user_id) AS user_count
  , COUNT(DISTINCT product_id) AS product_count
  , SUM(score) AS sum, AVG(score) AS avg,MAX(score) AS max,MIN(score) AS min
FROM
  review
;

๊ทธ๋ฃจํ•‘ํ•œ ๋ฐ์ดํ„ฐ์˜ ํŠน์ง•๋Ÿ‰ ๊ณ„์‚ฐ

  • GROUP BY ๊ตฌ๋ฌธ์„ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ๊ธˆ ๋” ์ž‘๊ฒŒ ๋ถ„ํ• 
SELECT
user_id,
  COUNT(*) AS total_count
  , COUNT(DISTINCT user_id) AS user_count
  , COUNT(DISTINCT product_id) AS product_count
  , SUM(score) AS sum, AVG(score) AS avg,MAX(score) AS max,MIN(score) AS min
FROM
  review
GROUP BY user_id
;

โ€ผ๏ธ GROUP BY๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ, SELECT ๊ตฌ๋ฌธ์—๋Š” ์ง‘์•ฝํ•จ์ˆ˜ ๋˜๋Š” Group by๊ตฌ๋ฌธ์— ์ง€์ •ํ•œ ์ปฌ๋Ÿผ๋งŒ์ด ์˜ฌ ์ˆ˜ ์žˆ์Œ! ( Group by๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ง€์ •์ปฌ๋Ÿผ์„ ์œ ๋‹ˆํฌ ํ‚ค๋กœ ์ƒˆ๋กœ์šด ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ!)

 

์ง‘์•ฝ ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ๊ฐ’๊ณผ ์ง‘์•ฝ ์ „์˜ ๊ฐ’์„ ๋™์‹œ์— ๋‹ค๋ฃจ๊ธฐ

์œˆ๋„ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ง‘์•ฝํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ์™€ ์›๋ž˜๊ฐ’์„ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ์Œ!

๐Ÿ’ก ์œˆ๋„์šฐ ํ•จ์ˆ˜๋ž€? : Group By์™€ ์œ ์‚ฌํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ์ง‘๊ณ„ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜!

but, Group By๋Š” ์ง‘๊ณ„๋œ ๊ฒฐ๊ณผ๋งŒ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐ˜๋ฉด, ์œˆ๋„์šฐ ํ•จ์ˆ˜๋Š” ๊ธฐ์กด ๋ฐ์ดํ„ฐ์— ์ง‘๊ณ„๋œ ๊ฐ’์„ ์ถ”๊ฐ€ํ•ด์„œ ๋‚˜ํƒ€๋‚ด์ค€๋‹ค!

# ์œˆ๋„์šฐ ํ•จ์ˆ˜ ๊ธฐ๋ณธ ํ˜•ํƒœ
ํ•จ์ˆ˜(ํ•จ์ˆ˜_์ ์šฉ_์—ด)OVER (PARTITIONBY ๊ทธ๋ฃน์—ด ORDERBY ์ˆœ์„œ์—ด)

PARTITION BY : Group By์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ

ORDER BY : Order By์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ (DESC : ๋‚ด๋ฆผ์ฐจ์ˆœ)

# ๊ฐœ๋ณ„ ๋ฆฌ๋ทฐ ์ ์ˆ˜์™€ ์‚ฌ์šฉ์ž ํ‰๊ท  ๋ฆฌ๋ทฐ ์ ์ˆ˜์˜ ์ฐจ์ด๋ฅผ ๊ตฌํ•˜๊ธฐ
SELECT
user_id, product_id, 
-- ๊ฐœ๋ณ„ ๋ฆฌ๋ทฐ ์ ์ˆ˜
score,
-- ์ „์ฒด ํ‰๊ท  ๋ฆฌ๋ทฐ ์ ์ˆ˜
AVG(score) OVER() as avg_score,
-- ์‚ฌ์šฉ์ž์˜ ํ‰๊ท  ๋ฆฌ๋ทฐ ์ ์ˆ˜
AVG(score) OVER(PARTITION BY user_id) AS user_avg_score,
-- ๊ฐœ๋ณ„ ๋ฆฌ๋ทฐ ์ ์ˆ˜์™€ ์‚ฌ์šฉ์ž ํ‰๊ท  ๋ฆฌ๋ทฐ ์ ์ˆ˜์˜ ์ฐจ์ด 
score - AVG(score) OVER(PARTITION BY user_id) AS user_avg_score_diff
FROM review; 
  • ์ง‘์•ฝํ•จ์ˆ˜๋กœ ์œˆ๋„ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ์ง‘์•ฝ ํ•จ์ˆ˜ ๋’ค์— OVER ๊ตฌ๋ฌธ์„ ๋ถ™์ด๊ณ , ์—ฌ๊ธฐ์— ์œˆ๋„ํ•จ์ˆ˜๋ฅผ ์ง€์ •
  • OVER ๊ตฌ๋ฌธ์— ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ํ…Œ์ด๋ธ” ์ „์ฒด์— ์ง‘์•ฝํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ๊ฐ’์ด ๋ฆฌํ„ด๋จ!
  • ๋งค๊ฐœ๋ณ€์ˆ˜์— PARTITION BY <์ปฌ๋Ÿผ ์ด๋ฆ„>์„ ์ง€์ •ํ•˜๋ฉด ํ•ด๋‹น ์ปฌ๋Ÿผ ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ทธ๋ฃนํ™”ํ•˜๊ณ  ์ง‘์•ฝํ•จ์ˆ˜ ์ ์šฉ

2. ๊ทธ๋ฃน ๋‚ด๋ถ€์˜ ์ˆœ์„œ

์œˆ๋„ํ•จ์ˆ˜๊ฐ€ ๋“ฑ์žฅํ•˜๋ฉด์„œ, SQL๋กœ ์ˆœ์„œ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์ด ๊ต‰์žฅํžˆ ์‰ฌ์›Œ์ง!

ORDER BY ๊ตฌ๋ฌธ์œผ๋กœ ์ˆœ์„œ ์ •์˜ํ•˜๊ธฐ

์œˆ๋„ ํ•จ์ˆ˜๋ž€, ํ…Œ์ด๋ธ” ๋‚ด๋ถ€์— ‘์œˆ๋„’๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•˜๊ณ , ํ•ด๋‹น ๋ฒ”์œ„ ๋‚ด๋ถ€์— ํฌํ•จ๋œ ๊ฐ’์„ ํŠน์ • ๋ ˆ์ฝ”๋“œ์—์„œ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ๋„์ž…ํ•œ ๊ฒƒ!

→ ์ด๋•Œ, ํ•ด๋‹น ๊ฐ’์˜ ์œ„์น˜๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ง€์ •ํ•ด์•ผํ•จ

→ OVER๊ตฌ๋ฌธ ๋‚ด๋ถ€์— ORDER BY ๊ตฌ๋ฌธ์‚ฌ์šฉํ•˜๋ฉด, ์œˆ๋„ ๋‚ด๋ถ€์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ์ˆœ์„œ ์ •์˜ ๊ฐ€๋Šฅ!

SELECT
  product_id
  , score
  -- ์ ์ˆ˜ ์ˆœ์„œ๋กœ ์œ ์ผํ•œ ์ˆœ์œ„
  , ROW_NUMBER()  OVER(ORDER BY score DESC) AS row
  -- ๊ฐ™์€ ์ˆœ์œ„ ํ—ˆ์šฉ, ์ˆœ์œ„
  , RANK()        OVER(ORDER BY score DESC) AS rank
  -- ๊ฐ™์€ ์ˆœ์œ„ ํ—ˆ์šฉ, ์ˆœ์œ„ ์ˆซ์ž๋Š” ๊ฑด๋„ˆ๋œ€
  , DENSE_RANK()  OVER(ORDER BY score DESC) AS dense_rank

  -- ํ˜„์žฌ ํ–‰๋ณด๋‹ค ์•ž์— ์žˆ๋Š” ํ–‰ ์ถ”์ถœ
  , LAG(product_id)       OVER(ORDER BY score DESC) AS lag1
  , LAG(product_id, 2)    OVER(ORDER BY score DESC) AS lag2

  -- ํ˜„์žฌ ํ–‰๋ณด๋‹ค ๋’ค์— ์žˆ๋Š” ํ–‰ ์ถ”์ถœ
  , LEAD(product_id)      OVER(ORDER BY score DESC) AS lead1
  , LEAD(product_id, 2)   OVER(ORDER BY score DESC) AS lead2
FROM popular_products
ORDER BY row
;
  • ORDER BY score DESC ๋กœ ํ…Œ์ด๋ธ” ๋‚ด๋ถ€์˜ ์ƒํ’ˆ์„ ์Šค์ฝ”์–ด๊ฐ€ ๋†’์€ ์ˆœ์œผ๋กœ ์ •๋ ฌ
  • ROW_NUMBER : ์ˆœ์„œ์— ์ˆœ์œ„๋ฒˆํ˜ธ๋ฅผ ๋ถ™์ด๊ธฐ
  • RANK ์™€ DENSE_RANK ํ•จ์ˆ˜๋Š”, ๊ฐ™์€ ์ˆœ์œ„์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์žˆ์„ ๋•Œ, ๋™์ผํ•œ ์ˆœ์œ„ ๋ฒˆํ˜ธ๋ฅผ ๋ถ™์ž„
    • RANK์˜ ๊ฒฝ์šฐ, ๊ฐ™์€ ์ˆœ์œ„์˜ ๋ ˆ์ฝ”๋“œ ๋’ค์˜ ์ˆœ์œ„ ๋ฒˆํ˜ธ๋ฅผ ๊ฑด๋„ˆ ๋œ€
    • 1, 1, 3, 4, ...
    • DENSE_RANK :์ˆœ์œ„ ๋ฒˆํ˜ธ๋ฅผ ๊ฑด๋„ˆ๋›ฐ์ง€ ์•Š์Œ
    • 1, 1, 2, 3, ...
  • LAG์™€ LEAD ํ•จ์ˆ˜๋Š”
    • ํ˜„์žฌ ํ–‰์„ ๊ธฐ์ค€์œผ๋กœ ์•ž์˜ ํ–‰ ๋˜๋Š” ๋’ค์˜ ํ–‰์„ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜
    • ๋‘๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ˆซ์ž๋ฅผ ์ง€์ •ํ•˜์—ฌ n๋ฒˆ์งธ ๊ฐ’ ์ถ”์ถœ

ORDER BY ๊ตฌ๋ฌธ๊ณผ ์ง‘์•ฝํ•จ์ˆ˜ ์กฐํ•ฉํ•˜๊ธฐ

  • ORDER BY์™€ SUM/AVG ๊ฐ™์€ ์ง‘์•ฝํ•จ์ˆ˜๋ฅผ ์กฐํ•ฉํ•˜๋ฉด, ์ง‘์•ฝ ํ•จ์ˆ˜์˜ ์ ์šฉ ๋ฒ”์œ„๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Œ!
# ORDER BY ๊ตฌ๋ฌธ์— ์ด์–ด์ง€๋Š” ROWS ๊ตฌ๋ฌธ์€ ์œˆ๋„ ํ”„๋ ˆ์ž„ ์ง€์ • ๊ตฌ๋ฌธ ์ฟผ๋ฆฌ
SELECT
  product_id
  , score
	-- ์ ์ˆ˜ ์ˆœ์„œ๋กœ ์œ ์ผํ•œ ์ˆœ์œ„๋ฅผ ๋ถ™์ž„
  , ROW_NUMBER()  OVER(ORDER BY score DESC) AS row

  -- ์ˆœ์œ„ ์ƒ์œ„์—์„œ ํ˜„์žฌ ํ–‰๊นŒ์ง€์˜ ์Šค์ฝ”์–ด๋ฅผ ๋ชจ๋‘ ๋”ํ•œ ๊ฐ’ ๊ณ„์‚ฐ
  , SUM(score)
      OVER(ORDER BY score DESC
          ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
      AS cum_score
  
  -- ํ˜„์žฌ ํ–‰ ๊ธฐ์ค€ ์ „/ํ›„ ์ด 3๊ฐœํ–‰์˜ ํ‰๊ท ์ ์ˆ˜ ๊ณ„์‚ฐ
  , AVG(score)
      OVER(ORDER BY score DESC
          ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
      AS local_avg
  
  -- FIRST_VALUE : ์ˆœ์œ„๊ฐ€ ๋†’์€ ์ƒํ’ˆ ID(์œˆ๋„ ๋‚ด๋ถ€์˜ ์ฒซ ๋ ˆ์ฝ”๋“œ)
  , FIRST_VALUE(product_id)
      OVER(ORDER BY score DESC
          ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
      AS first_value
  
  -- LAST VALUE : ์ˆœ์œ„๊ฐ€ ๋‚ฎ์€ ์ƒํ’ˆ ID(์œˆ๋„ ๋‚ด๋ถ€์˜ ๋งˆ์ง€๋ง‰ ๋ ˆ์ฝ”๋“œ)
  , LAST_VALUE(product_id)
      OVER(ORDER BY score DESC
          ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
      AS last_value

FROM popular_products
ORDER BY row
;

์œˆ๋„์šฐ ํ”„๋ ˆ์ž„ ์ง€์ •

  • ํ”„๋ ˆ์ž„ ์ง€์ •์ด๋ž€? ํ˜„์žฌ ๋ ˆ์ฝ”๋“œ ์œ„์น˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ๋Œ€์ ์ธ ์œˆ๋„๋ฅผ ์ •์˜ํ•˜๋Š” ๊ตฌ๋ฌธ - 3๊ฐ€์ง€ ์ข…๋ฅ˜
  • ROWS BETWEEEN {start} AND {end}
    • start์™€ end์—๋Š”
      • CURRENT ROW : ํ˜„์žฌ ํ–‰
      • n PRECEDING : nํ–‰ ์•ž
      • n FOLLOWING : nํ–‰ ๋’ค
      • UNBOUNDED PRECEDING : ์ด์ „ ํ–‰ ์ „๋ถ€
      • UNBOUNDED FOLLOWING : ์ดํ›„ ํ–‰ ์ „๋ถ€
  • array_agg : ๋‹ค์ˆ˜์˜ row๋“ค์˜ ํŠน์ • ์นผ๋Ÿผ๊ฐ’์„ ํ•˜๋‚˜์˜ ๋ฐฐ์—ด์— ๋‹ด๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜
# ๋ฒ”์œ„ ๋‚ด๋ถ€ ์ƒํ’ˆ ID๋ฅผ ์ง‘์•ฝํ•˜๋Š” ์ฟผ๋ฆฌ
SELECT
  product_id
  , ROW_NUMBER()  OVER(ORDER BY score DESC) AS row

  -- ๊ฐ€์žฅ ์•ž ์ˆœ์œ„๋ถ€ํ„ฐ, ๋’ท ์ˆœ์œ„๊นŒ์ง€์˜ ๋ฒ”์œ„๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ƒํ’ˆ ID ์ง‘์•ฝ
  , array_agg(product_id)
      OVER(ORDER BY score DESC
      ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
  AS whole_agg

  -- ๊ฐ€์žฅ ์•ž ์ˆœ์œ„๋ถ€ํ„ฐ ํ˜„์žฌ ์ˆœ์œ„๊นŒ์ง€์˜ ๋ฒ”์œ„๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ƒํ’ˆ ID ์ง‘์•ฝ
  , array_agg(product_id)
      OVER(ORDER BY score DESC
          ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
  AS cum_agg

  -- ์ˆœ์œ„ ํ•˜๋‚˜ ์•ž/๋’ค๊นŒ์ง€์˜ ๋ฒ”์œ„๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ƒํ’ˆ ID ์ง‘์•ฝ
  , array_agg(product_id)
      OVER(ORDER BY score DESC
          ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
  AS local_agg
FROM popular_products
WHERE category='action'
ORDER BY row
;
  • ์œˆ๋„ ํ•จ์ˆ˜์— ํ”„๋ ˆ์ž„ ์ง€์ •์„ ํ•˜์ง€ ์•Š์œผ๋ฉด, ORDER BY ๊ตฌ๋ฌธ์ด ์—†๋Š” ๊ฒฝ์šฐ ๋ชจ๋“  ํ–‰, ORDER BY ๊ตฌ๋ฌธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ฒซ ํ–‰์—์„œ ํ˜„์žฌ ํ–‰๊นŒ์ง€๊ฐ€ ๋””ํดํŠธ๋กœ ์ง€์ •!

PARTITION BY์™€ ORDER BY ์กฐํ•ฉํ•˜๊ธฐ

  • PARTITION BY์™€ ORDER BY ๊ตฌ๋ฌธ์„ ์กฐํ•ฉํ•ด ์นดํ…Œ๊ณ ๋ฆฌ๋“ค์˜ ์ˆœ์œ„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์ฟผ๋ฆฌ
SELECT
	category, product_id, score,
	-- ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ„๋กœ ์ ์ˆ˜ ์ˆœ์„œ๋กœ ์ •๋ ฌํ•˜๊ณ , ์œ ์ผํ•œ ์ˆœ์œ„๋ฅผ ๋ถ™์ž„
	ROW_NUMBER() OVER (PARTITION BY category ORDER BY score DESC) AS row
	-- ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ„๋กœ ๊ฐ™์€ ์ˆœ์œ„๋ฅผ ํ—ˆ๊ฐ€ํ•˜๊ณ  ์ˆœ์œ„๋ฅผ ๋ถ™์ž„
	, RANK() OVER (PARTITION BY category ORDER BY score DESC) AS rank
	
	-- ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ๊ฐ™์€ ์ˆœ์œ„๊ฐ€ ์žˆ์„ ๋•Œ
	-- ๊ฐ™์€ ์ˆœ์œ„ ๋‹ค์Œ์— ์žˆ๋Š” ์ˆœ์œ„๋ฅผ ๊ฑด๋„ˆ ๋›ฐ๊ณ  ์ˆœ์œ„๋ฅผ ๋ถ™์ž„
	, DENSE_RANK()
	OVER (PARTITION BY category ORDER BY score DESC) AS dense_rank
	FROM popular_products ORDER BY category, row;

  • ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ƒ์œ„ n๊ฐœ ์ถ”์ถœํ•˜๊ธฐ

์œˆ๋„ํ•จ์ˆ˜๋ฅผ WHERE๊ตฌ๋ฌธ์— ์ž‘์„ฑํ•  ์ˆ˜ ์—†์Œ

→ ์œˆ๋„ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ๋ฅผ ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ ๋งŒ๋“ค๊ณ , WHERE๊ตฌ๋ฌธ ์ ์šฉํ•˜๊ธฐ!

SELECT * FROM
-- ์„œ๋ธŒ์ฟผ๋ฆฌ ๋‚ด๋ถ€์—์„œ ์ˆœ์œ„ ๊ณ„์‚ฐํ•˜๊ธฐ
( SELECT category, product_id, score, 
	-- ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ์ ์ˆ˜ ์ˆœ์„œ๋กœ ์œ ์ผํ•œ ์ˆœ์œ„๋ฅผ ๋ถ™์ž„
	ROW_NUMBER() OVER (PARTITION BY category ORDER BY score DESC) AS rank
	FROM popular_products
) AS popular_products_with_rank
-- ์™ธ๋ถ€์ฟผ๋ฆฌ์—์„œ ์ˆœ์œ„ ํ™œ์šฉํ•ด ์••์ถ•ํ•˜๊ธฐ
WHERE rank <= 2 ORDER BY category, rank;

  • ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ˆœ์œ„ ์ˆœ์„œ์—์„œ ์ƒ์œ„ 1๊ฐœ์˜ ์ƒํ’ˆ ID๋งŒ์„ ์ถ”์ถœํ•˜๊ธฐ

→ FIRST_VALUE ์œˆ๋„์šฐ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , SELECT DISTINCT ๊ตฌ๋ฌธ์œผ๋กœ ๊ฒฐ๊ณผ ์ง‘์•ฝํ•˜๊ธฐ!

-- DISTINCT ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•ด ์ค‘๋ณต ์ œ๊ฑฐํ•˜๊ธฐ!
SELECT DISTINCT category
	-- ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ์ˆœ์œ„ ์ตœ์ƒํ’ˆ ์ƒํ’ˆ ID ์ถ”์ถœํ•˜๊ธฐ
, FIRST_VALUE(product_id)
	OVER (PARTITION BY category ORDER BY score DESC
		ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS product_id
FROM popular_products;

  • DISTINCT ์•ˆ ์“ธ ๊ฒฝ์šฐ!

3. ์„ธ๋กœ ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๋กœ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

  • ํ–‰ ๋‹จ์œ„๋กœ ์ €์žฅ๋œ ‘์„ธ๋กœ ๊ธฐ๋ฐ˜’์„, ์—ด ๋˜๋Š” ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ฌธ์ž์—ด ๋“ฑ์˜ ‘๊ฐ€๋กœ๊ธฐ๋ฐ˜’์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ!
  • SQL์—์„  ํ–‰(๋ ˆ์ฝ”๋“œ) ๊ธฐ๋ฐ˜์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ์ด๋ฏ€๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ ์ตœ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ–‰์œผ๋กœ ๋ถ„ํ• ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Œ! but, ์ตœ์ข… ์ถœ๋ ฅ์—์„  ๋ฐ์ดํ„ฐ๋ฅผ ์—ด๋กœ ์ „๊ฐœํ•ด์•ผ ๊ฐ€๋…์„ฑ์ด ๋†’์€ ๊ฒฝ์šฐ ๋งŽ๋‹ค

ํ–‰์„ ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

SQL์—์„œ ์—ด์€ ๊ณ ์ •์ ์ด์–ด์•ผ ํ•จ! → ์—ด๋กœ ์ „๊ฐœํ•  ๋ฐ์ดํ„ฐ์˜ ์ข…๋ฅ˜ ๋˜๋Š” ์ˆ˜๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•จ!

# ํ–‰์œผ๋กœ ์ €์žฅ๋œ ์ง€ํ‘œ๋ฅผ ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ฟผ๋ฆฌ
# Group by dt๋กœ ๋‚ ์งœ๋ฅผ 1๊ฐœ์˜ ๋ ˆ์ฝ”๋“œ๋กœ ์ง‘์•ฝํ•˜๊ฒŒ ํ•จ!
SELECT dt, MAX(CASE WHEN indicator = 'impressions' THEN val END) AS impressions
, MAX(CASE WHEN indicator = 'sessions' THEN val END) AS sessions,
 MAX(CASE WHEN indicator = 'users' THEN val END) AS users
FROM daily_kpi
GROUP BY dt ORDER BY dt;

  • ์ด๋•Œ, MAX๋ฅผ ์จ์ค€ ์ด์œ  -> SELECT ๋ฌธ์— GROUP BY ๋ฌธ์— ์‚ฌ์šฉ๋œ ์ปฌ๋Ÿผ์ด๋‚˜ ์ง‘๊ณ„ํ•จ์ˆ˜๋งŒ์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—!

ํ–‰์„ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•œ ๋ฌธ์ž์—ด๋กœ ์ง‘์•ฝํ•˜๊ธฐ

  • ์—ด์˜ ์ข…๋ฅ˜์™€ ์ˆ˜๋ฅผ ๋ชจ๋ฅผ ๊ฒฝ์šฐ์—๋Š” ํ–‰์„ ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์“ธ ์ˆ˜ ์—†์Œ!

ํ•œ๋ฒˆ์˜ ์ฃผ๋ฌธ์œผ๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ƒํ’ˆ์„ ๊ตฌ๋งคํ–ˆ์„ ๋•Œ → ์ด๋ฅผ ์ƒํ’ˆ๋ณ„๋กœ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋‚˜๋ˆ„์–ด ์ €์žฅํ•˜๋Š” ํ…Œ์ด๋ธ”! ๊ตฌ๋งคid๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ ˆ์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜๋กœ ์ง‘์•ฝํ•˜๊ณ  ์‹ถ์–ด๋„ ์ƒํ’ˆ์„ ๋ช‡ ๊ฐœ ์ฃผ๋ฌธํ–ˆ๋Š”์ง€ ๋ฏธ๋ฆฌ ์•Œ ์ˆ˜ ์—†์Œ! → ์—ด๋กœ ์ง‘๊ณ„๊ฐ€ ์–ด๋ ต๋‹ค!

→ ํ–‰์„ ์ง‘์•ฝํ•ด์„œ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ! string_agg ํ•จ์ˆ˜ ์ด์šฉ

SELECT purchase_id
-- ์ƒํ’ˆ id๋ฅผ ๋ฐฐ์—ด์— ์ง‘์•ฝํ•˜๊ณ  ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ
, string_agg(product_id, ',') AS product_ids
, SUM(price) as amount
FROM purchase_detail_log GROUP BY purchase_id ORDER BY purchase_id;

4. ๊ฐ€๋กœ ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ๋ฅผ ์„ธ๋กœ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

  • ๊ฐ€๋กœ ๊ธฐ๋ฐ˜์„ ์„ธ๋กœ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•œ ์ผ์ด ์•„๋‹˜!
  • ์ด๋ฏธ ๋ฐ์ดํ„ฐ๊ฐ€ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ์—ด ๊ธฐ๋ฐ˜์˜ ํ˜•์‹์œผ๋กœ ์ €์žฅ๋œ ๊ฒฝ์šฐ ๋งŽ์Œ! → ๋ณ€ํ™˜ํ•ด์•ผํ•จ!

์—ด๋กœ ํ‘œํ˜„๋œ ๊ฐ’์„ ํ–‰์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

๋ฐ์ดํ„ฐ์˜ ์ˆ˜๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ๋Š” ๋ฐ์ดํ„ฐ!

  • ์ปฌ๋Ÿผ์œผ๋กœ ํ‘œํ˜„๋œ ๊ฐ€๋กœ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ์˜ ํŠน์ง• : ๋ฐ์ดํ„ฐ์˜ ์ˆ˜๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฒƒ!

→ ์œ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋ฉด, q1 ~ q4๊นŒ์ง€ ๋ชจ๋‘ 4๊ฐœ์˜ ๋ฐ์ดํ„ฐ → ๋ฐ์ดํ„ฐ ์ˆ˜ ๋งŒํผ์˜ ์ผ๋ จ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ ํ”ผ๋ฒ—ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค๊ณ  CROSS JOIN ํ•˜๊ธฐ!

# ํ”ผ๋ฒ—ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ•˜๊ณ , CASE ์‹์œผ๋กœ ๋ ˆ์ด๋ธ” ์ด๋ฆ„๊ณผ ๋งค์ถœ๊ฐ’์„ ์ถ”์ถœํ•ด์„œ ์—ด์„ ํ–‰์œผ๋กœ ๋ณ€ํ™˜!
SELECT
	q.year, 
-- Q1์—์„œ Q4๊นŒ์ง€์˜ ๋ ˆ์ด๋ธ” ์ด๋ฆ„ ์ถœ๋ ฅํ•˜๊ธฐ
CASE 
	WHEN p.idx = 1 THEN 'q1'
	WHEN p.idx = 2 THEN 'q2'
	WHEN p.idx = 3 THEN 'q3'
	WHEN p.idx = 4 THEN 'q4'
END AS quarter
-- Q1์—์„œ Q4๊นŒ์ง€์˜ ๋งค์ถœ ์ถœ๋ ฅํ•˜๊ธฐ
, CASE
	WHEN p.idx = 1 THEN q.q1
	WHEN p.idx = 2 THEN q.q2
	WHEN p.idx = 3 THEN q.q3
	WHEN p.idx = 4 THEN q.q4
END AS sales
FROM
	quarterly_sales AS q
CROSS JOIN
-- ํ–‰์œผ๋กœ ์ „๊ฐœํ•˜๊ณ  ์‹ถ์€ ์—ด์˜ ์ˆ˜๋งŒํผ ์ˆœ๋ฒˆ ํ…Œ์ด๋ธ” ๋งŒ๋“ค๊ธฐ
( SELECT 1 AS idx UNION ALL SELECT 2 AS idx UNION ALL SELECT 3 AS idx UNION ALL SELECT 4 AS idx) AS p;

	

์ž„์˜์˜ ๊ธธ์ด๋ฅผ ๊ฐ€์ง„ ๋ฐฐ์—ด์„ ํ–‰์œผ๋กœ ์ „๊ฐœํ•˜๊ธฐ

๋ฐ์ดํ„ฐ ๊ธธ์ด๊ฐ€ ํ™•์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ์กฐ๊ธˆ ๋ณต์žก!

# ํ”ผ๋ฒ—ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ•˜๊ณ , CASE ์‹์œผ๋กœ ๋ ˆ์ด๋ธ” ์ด๋ฆ„๊ณผ ๋งค์ถœ๊ฐ’์„ ์ถ”์ถœํ•ด์„œ ์—ด์„ ํ–‰์œผ๋กœ ๋ณ€ํ™˜!
SELECT
	q.year, 
-- Q1์—์„œ Q4๊นŒ์ง€์˜ ๋ ˆ์ด๋ธ” ์ด๋ฆ„ ์ถœ๋ ฅํ•˜๊ธฐ
CASE 
	WHEN p.idx = 1 THEN 'q1'
	WHEN p.idx = 2 THEN 'q2'
	WHEN p.idx = 3 THEN 'q3'
	WHEN p.idx = 4 THEN 'q4'
END AS quarter
-- Q1์—์„œ Q4๊นŒ์ง€์˜ ๋งค์ถœ ์ถœ๋ ฅํ•˜๊ธฐ
, CASE
	WHEN p.idx = 1 THEN q.q1
	WHEN p.idx = 2 THEN q.q2
	WHEN p.idx = 3 THEN q.q3
	WHEN p.idx = 4 THEN q.q4
END AS sales
FROM
	quarterly_sales AS q
CROSS JOIN
-- ํ–‰์œผ๋กœ ์ „๊ฐœํ•˜๊ณ  ์‹ถ์€ ์—ด์˜ ์ˆ˜๋งŒํผ ์ˆœ๋ฒˆ ํ…Œ์ด๋ธ” ๋งŒ๋“ค๊ธฐ
( SELECT 1 AS idx UNION ALL SELECT 2 AS idx UNION ALL SELECT 3 AS idx UNION ALL SELECT 4 AS idx) AS p;

์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ์ƒํ’ˆ id๋ฅผ ํฌํ•จํ•œ ๋ ˆ์ฝ”๋“œ!

ํ…Œ์ด๋ธ” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ! unnest() ํ•จ์ˆ˜

  • ํ…Œ์ด๋ธ” ํ•จ์ˆ˜: ๋ฆฌํ„ด๊ฐ’์ด ํ…Œ์ด๋ธ”์ธ ํ•จ์ˆ˜! ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐฐ์—ด์„ ๋ฐ›๊ณ , ๋ฐฐ์—ด์„ ๋ ˆ์ฝ”๋“œ ๋ถ„ํ• ํ•ด์„œ ๋ฆฌํ„ดํ•ด์คŒ!
SELECT unnest(ARRAY['A001','A002','A003']) AS product_id;

SELECT purchase_id, product_id
	FROM purchase_log AS p CROSS JOIN unnest(string_to_array(product_ids, ',')) AS product_id
-- string_to_array ํ•จ์ˆ˜๋กœ ๋ฌธ์ž์—ด์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , unnest ํ•จ์ˆ˜๋กœ ํ…Œ์ด๋ธ”๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ!

  • regexp_split_to_table: ๋ฌธ์ž์—ด์„ ๊ตฌ๋ถ„์ž๋กœ ๋ถ„ํ• ํ•ด์„œ ํ…Œ์ด๋ธ”ํ™”ํ•˜๋Š” ํ•จ์ˆ˜
SELECT purchase_id, regexp_split_to_table(product_ids, ',') AS product_id
FROM purchase_log;

๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2024/07   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
๊ธ€ ๋ณด๊ด€ํ•จ