๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

Window ํ•จ์ˆ˜

SQL Server์—์„œ Window ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์™€ ์ด์œ 

  • #sql
  • #window

SQL์—์„œ ์œˆ๋„์šฐ ํ•จ์ˆ˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘๊ณ„ํ•˜์ง€ ์•Š๊ณ  ํ˜„์žฌ ํ–‰๊ณผ ๊ด€๋ จ๋œ ํ–‰ ์ง‘ํ•ฉ์— ๋Œ€ํ•ด ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋ถ€์ธ ์„ฑ๋ช…

ํ•œ๊ตญ์–ด ์‹ค๋ ฅ์ด ๋ถ€์ ํ•˜์—ฌ ์ด ๊ธ€์ด ๊ตฌ๊ธ€ ๋ฒˆ์—ญ๊ธฐ๋ฅผ ์ฃผ๋กœ ํ™œ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€์ •ํ™•ํ•œ ๋ฌธ๋ฒ•๊ณผ ์–ดํœ˜๊ฐ€ ์žˆ์„์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์  ์–‘ํ•ด ๋ถ€ํƒ๋“œ๋ฆฌ๋ฉฐ, ์ถ”ํ›„์— ๋‹ค์‹œ ๊ฒ€ํ† ํ•˜์—ฌ ์ˆ˜์ •ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

AVG, MIN ๋ฐ MAX

๋‹ค์Œ์€ AVG, MIN, MAX๋ฅผ ์‚ฌ์šฉํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ฐ„๋‹จํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

SELECT
    id,
    name,
    category,
    AVG(price) OVER(),
    MIN(price) OVER(),
    MAX(price) OVER()
FROM books;

์ถœ๋ ฅ์€ ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ–๋Š” ์„ธ ๊ฐœ์˜ ์ƒˆ๋กœ์šด ์—ด๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

idnamecategoryavg(price)min(price)max(price)
1book1motivation50.105.20120.90
2book2motivation50.105.20120.90
3book3health50.105.20120.90

ํ‰๊ท  ๊ฐ€๊ฒฉ์—์„œ ๊ฐ€๊ฒฉ ์ฐจ์ด๋ฅผ ๊ณ„์‚ฐ

๋‹ค์Œ์œผ๋กœ, OVER๋ฅผ ์ด์šฉํ•ด ๊ฐ€๊ฒฉ ์ฐจ์ด์™€ ๋ฐฑ๋ถ„์œจ์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SELECT
    id,
    name,
    category,
    ROUND(AVG(price) OVER(), 2),
    ROUND((price - AVG(price) OVER()), 2) AS diff_avg,
    ROUND(ABS(price - AVG(price) OVER()) / (AVG(price) OVER() * 100)) AS pct_diff_avg
FROM books;

๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์— ํ‘œ์‹œ๋œ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

idnamecategoryavg(price)diff_avgpct_diff_avg
1book1motivation50.10-20.10xx
2book2motivation50.105.60xx
3book3health50.1010.80xx

ํŒŒํ‹ฐ์…˜๋‹

PARTITION BY๋Š” GROUPBY์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜์ง€๋งŒ, ๋ถ„ํ• ์€ OVER() ์ ˆ ๋‚ด์—์„œ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํŒŒํ‹ฐ์…˜

SELECT
    id,
    name,
    category,
    publisher,
    AVG(price) OVER(PARTITION BY category) AS avg_cat,
    AVG(price) OVER(PARTITION BY category, publisher) AS avg_cat_pub
FROM books;

์•„๋ž˜์™€ ์œ ์‚ฌํ•œ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

idnamecategorypublisheravg_catavg_cat_pub
1book1motivationpelangi30.0032.00
2book2motivationpopular30.0025.00
3book3healthpelangi20.8020.80
4book4motivationpopular30.0025.00
5book5healthpelangi20.8020.80

์ฒซ ๋ฒˆ์งธ ํŒŒํ‹ฐ์…˜์€ category ์—ด์„ ๊ธฐ์ค€์œผ๋กœ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ category์— ์†ํ•˜๋Š” ๊ฐ ์ฑ…์€ ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ํŒŒํ‹ฐ์…˜์€ category ์—ด๊ณผ publisher ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ category์™€ publisher์— ์†ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค๋„ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค.

์ˆœ์œ„

Row Number

์ˆœ์œ„๋Š” ์ฐฝ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ์—ด์„ ๊ธฐ์ค€์œผ๋กœ ๊ณ„์‚ฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SELECT
    id,
    name,
    category,
    price,
    ROW_NUMBER() OVER(ORDER BY price DESC) AS rank_by_price
FROM books;
idnamecategorypricerank_by_price
1book1motivation99.991
2book2motivation70.002
3book3health30.503
4book4motivation10.004
5book5health5.805

ํ‘œ๋Š” ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์–ป์€ ์ˆœ์œ„์— ๋”ฐ๋ผ ํ–‰์„ ๋‚˜์—ดํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, ์ˆœ์œ„๋ฅผ ์—ด, ์˜ˆ๋ฅผ ๋“ค์–ด category์— ๋”ฐ๋ผ ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SELECT
    id,
    name,
    category,
    price,
    ROW_NUMBER() OVER(PARTITION BY category ORDER BY price DESC) AS rank_partition_by_price
FROM books;

์ด์ œ ๊ฒฐ๊ณผ๋Š” ์ž์ฒด ํŒŒํ‹ฐ์…˜ ๋‚ด์˜ ํ–‰์„ ์ˆœ์œ„๋ฅผ ๋งค๊น๋‹ˆ๋‹ค.

idnamecategorypricerank_partition_by_price
1book1motivation99.991
2book2motivation70.002
3book3health30.501
4book5health10.002
5book4motivation5.801

๋ฌธ์ œ ์ง„์ˆ : ์ฑ…์ด ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ƒ์œ„ 3์œ„์ด๋ฉด "์˜ˆ", ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด "์•„๋‹ˆ์š”"๋กœ ์—ด์„ ์ฑ„์šฐ๋Š” ์ƒˆ ์—ด์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด CASE ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SELECT
    id,
    name,
    category,
    price,
    CASE
        WHEN ROW_NUMBER() OVER(PARTITION BY category ORDER BY price DESC) <= 3 THEN 'Yes'
        ELSE 'No'
    END AS top3_of_category
FROM books;

๊ฒฐ๊ณผ๊ฐ€ ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

idnamecategorypricetop3_of_category
1book1motivation99.99Yes
2book2motivation70.00Yes
3book3motivation30.50Yes
4book5motivation10.00No
5book4motivation5.80No
6book6health100.00Yes

Rank ๋ฐ Dense Rank

Rank์™€ dense rank๋Š” ROW_NUMBER๊ฐ€ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋ฏธ๋ฌ˜ํ•จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ ์—ด์— ๋Œ€ํ•ด ์ •ํ™•ํžˆ ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ€์ง„ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ˆœ์œ„๋ฅผ ๋งค๊ธฐ๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

SELECT
    id,
    name,
    category,
    price,
    RANK() OVER(PARTITION BY category ORDER BY price DESC) AS rank_partition_by_price
FROM books;
idnamecategorypricerank_partition_by_price
1book1motivation99.991
2book2motivation70.002
3book3motivation70.002
4book5motivation60.504
5book4motivation60.504
6book6motivation30.006

๋™์ผํ•œ ๋ ˆ์ฝ”๋“œ์˜ ์ˆœ์œ„๋Š” ๋™์ผํ•˜์ง€๋งŒ, ํ›„์† ์ˆœ์œ„๋Š” ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ–๋Š” ๋ ˆ์ฝ”๋“œ์˜ ์ˆ˜์— ๋”ฐ๋ผ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด, ๋ฐ€์ง‘ ์ˆœ์œ„๋Š” ์ˆœ์œ„ ์ˆœ์„œ๋ฅผ ๋ณด์กดํ•˜๊ณ  ํ›„์† ์ˆœ์œ„๋ฅผ ๊ฑด๋„ˆ๋›ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ๋™์ผํ•œ ์ฟผ๋ฆฌ์—์„œ RANK ํ‚ค์›Œ๋“œ๋ฅผ DENSE_RANK๋กœ ๋Œ€์ฒดํ–ˆ์„ ๋•Œ ์–ป์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

idnamecategorypricerank_partition_by_price
1book1motivation99.991
2book2motivation70.002
3book3motivation70.002
4book5motivation60.503
5book4motivation60.503
6book6motivation30.004

Lag ๋ฐ Lead

  • Lag - ์ˆœ์œ„ ๋‚ด์—์„œ ์ด์ „ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
  • Lead - ์ˆœ์œ„ ๋‚ด์—์„œ ๋‹ค์Œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
SELECT
    id,
    name,
    category,
    price,
    LAG(price) OVER(PARTITION BY category ORDER BY price) a,
    LEAD(price) OVER(PARTITION BY category ORDER BY price) b
FROM books;

์œ„ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜ ํ‘œ์— ํ‘œ์‹œ๋œ ๊ฒฐ๊ณผ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

idnamecategorypriceab
1book1motivation99.99null70.00
2book2motivation70.0099.9970.00
3book3motivation70.0070.0060.50
4book5motivation60.5070.0060.50
5book4motivation60.5060.5030.00
6book6motivation30.0060.50null

lag์™€ lead๋Š” ๋‘˜ ๋‹ค ์‚ฌ์šฉํ•  ๊ธฐ๊ฐ„์„ ์ง€์‹œํ•˜๋Š” ์ถ”๊ฐ€์ ์ธ ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

LAG(price, 2)
LEAD(price, 5)

์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

์œˆ๋„์šฐ ํ•จ์ˆ˜์˜ ๋ช‡ ๊ฐ€์ง€ ์‚ฌ์šฉ๋ฒ•

  • ์ˆœ์œ„
  • ์ด๋™ ํ‰๊ท 
  • ๋ˆ„์ (๋ˆ„์ )
  • ๊ธฐ๊ฐ„๋ณ„ ๋น„๊ต
  • ๋ฐฑ๋ถ„์œ„์ˆ˜ ๊ณ„์‚ฐ
  • ์‹œ์ž‘๊ฐ€์™€ ๋งˆ๊ฐ๊ฐ€
  • ์‹œ๊ณ„์—ด ๋ถ„์„

์ฐธ๊ณ 

Mo Chen. WINDOW FUNCTIONS | Advanced SQL.ย YouTube. https://www.youtube.com/watch?v=efrR9eP2hUo