1-- =============================================================================
2-- PostgreSQL μλμ° ν¨μ μμ
3-- Window Functions (Analytic Functions)
4-- =============================================================================
5
6-- λ¨Όμ μ΄μ μμ νμΌλ€μ μ€ννμ¬ ν
μ΄λΈκ³Ό λ°μ΄ν°λ₯Ό μμ±νμΈμ.
7
8-- =============================================================================
9-- 1. κΈ°λ³Έ μλμ° ν¨μ ꡬ쑰
10-- =============================================================================
11
12-- OVER() - μ 체 ν
μ΄λΈμ νλμ μλμ°λ‘
13SELECT
14 first_name,
15 last_name,
16 salary,
17 SUM(salary) OVER() AS total_salary,
18 ROUND(AVG(salary) OVER(), 2) AS avg_salary,
19 COUNT(*) OVER() AS total_count
20FROM employees;
21
22-- =============================================================================
23-- 2. PARTITION BY - κ·Έλ£Ήλ³ μλμ°
24-- =============================================================================
25
26-- λΆμλ³λ‘ νν°μ
λλκΈ°
27SELECT
28 e.first_name,
29 e.last_name,
30 d.dept_name,
31 e.salary,
32 SUM(e.salary) OVER(PARTITION BY e.dept_id) AS dept_total,
33 ROUND(AVG(e.salary) OVER(PARTITION BY e.dept_id), 2) AS dept_avg,
34 COUNT(*) OVER(PARTITION BY e.dept_id) AS dept_count
35FROM employees e
36JOIN departments d ON e.dept_id = d.dept_id
37ORDER BY d.dept_name, e.salary DESC;
38
39-- λΆμλ³ κΈμ¬ λΉμ¨
40SELECT
41 e.first_name,
42 e.last_name,
43 d.dept_name,
44 e.salary,
45 SUM(e.salary) OVER(PARTITION BY e.dept_id) AS dept_total,
46 ROUND(100.0 * e.salary / SUM(e.salary) OVER(PARTITION BY e.dept_id), 2) AS salary_pct
47FROM employees e
48JOIN departments d ON e.dept_id = d.dept_id
49ORDER BY d.dept_name, salary_pct DESC;
50
51-- =============================================================================
52-- 3. μμ ν¨μ (Ranking Functions)
53-- =============================================================================
54
55-- ROW_NUMBER: μ°μ λ²νΈ (λμ μλ λ€λ₯Έ λ²νΈ)
56-- RANK: λμ μλ κ°μ μμ, λ€μ μμ 건λλ
57-- DENSE_RANK: λμ μλ κ°μ μμ, λ€μ μμ μ°μ
58
59SELECT
60 first_name,
61 last_name,
62 salary,
63 ROW_NUMBER() OVER(ORDER BY salary DESC) AS row_num,
64 RANK() OVER(ORDER BY salary DESC) AS rank,
65 DENSE_RANK() OVER(ORDER BY salary DESC) AS dense_rank
66FROM employees;
67
68-- λΆμλ³ κΈμ¬ μμ
69SELECT
70 e.first_name,
71 e.last_name,
72 d.dept_name,
73 e.salary,
74 RANK() OVER(PARTITION BY e.dept_id ORDER BY e.salary DESC) AS dept_salary_rank
75FROM employees e
76JOIN departments d ON e.dept_id = d.dept_id
77ORDER BY d.dept_name, dept_salary_rank;
78
79-- λΆμλ³ Top 2 κΈμ¬μ
80SELECT * FROM (
81 SELECT
82 e.first_name,
83 e.last_name,
84 d.dept_name,
85 e.salary,
86 ROW_NUMBER() OVER(PARTITION BY e.dept_id ORDER BY e.salary DESC) AS rn
87 FROM employees e
88 JOIN departments d ON e.dept_id = d.dept_id
89) ranked
90WHERE rn <= 2;
91
92-- NTILE: Nκ°μ λ²ν·μΌλ‘ λΆν
93SELECT
94 first_name,
95 last_name,
96 salary,
97 NTILE(4) OVER(ORDER BY salary DESC) AS salary_quartile
98FROM employees;
99
100-- =============================================================================
101-- 4. μ€νμ
ν¨μ (LAG, LEAD, FIRST_VALUE, LAST_VALUE)
102-- =============================================================================
103
104-- LAG: μ΄μ ν κ°
105-- LEAD: λ€μ ν κ°
106SELECT
107 first_name,
108 hire_date,
109 LAG(first_name, 1) OVER(ORDER BY hire_date) AS prev_hire,
110 LEAD(first_name, 1) OVER(ORDER BY hire_date) AS next_hire
111FROM employees
112ORDER BY hire_date;
113
114-- κΈμ¬ λ³ν λΆμ
115SELECT
116 first_name,
117 salary,
118 LAG(salary) OVER(ORDER BY emp_id) AS prev_salary,
119 salary - LAG(salary) OVER(ORDER BY emp_id) AS salary_diff
120FROM employees;
121
122-- λΆμ λ΄ μ΄μ /λ€μ μ§μ
123SELECT
124 e.first_name,
125 d.dept_name,
126 e.salary,
127 LAG(e.salary) OVER(PARTITION BY e.dept_id ORDER BY e.salary) AS lower_salary,
128 LEAD(e.salary) OVER(PARTITION BY e.dept_id ORDER BY e.salary) AS higher_salary
129FROM employees e
130JOIN departments d ON e.dept_id = d.dept_id
131ORDER BY d.dept_name, e.salary;
132
133-- FIRST_VALUE, LAST_VALUE
134SELECT
135 e.first_name,
136 d.dept_name,
137 e.salary,
138 FIRST_VALUE(e.first_name) OVER(
139 PARTITION BY e.dept_id ORDER BY e.salary DESC
140 ) AS highest_paid,
141 LAST_VALUE(e.first_name) OVER(
142 PARTITION BY e.dept_id ORDER BY e.salary DESC
143 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
144 ) AS lowest_paid
145FROM employees e
146JOIN departments d ON e.dept_id = d.dept_id;
147
148-- =============================================================================
149-- 5. μ§κ³ μλμ° ν¨μ
150-- =============================================================================
151
152-- λμ ν©κ³ (Running Total)
153SELECT
154 first_name,
155 hire_date,
156 salary,
157 SUM(salary) OVER(ORDER BY hire_date) AS running_total
158FROM employees
159ORDER BY hire_date;
160
161-- λΆμλ³ λμ ν©κ³
162SELECT
163 e.first_name,
164 d.dept_name,
165 e.salary,
166 SUM(e.salary) OVER(
167 PARTITION BY e.dept_id
168 ORDER BY e.emp_id
169 ) AS dept_running_total
170FROM employees e
171JOIN departments d ON e.dept_id = d.dept_id
172ORDER BY d.dept_name, e.emp_id;
173
174-- μ΄λ νκ· (Moving Average)
175SELECT
176 first_name,
177 salary,
178 ROUND(AVG(salary) OVER(
179 ORDER BY emp_id
180 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
181 ), 2) AS moving_avg_3
182FROM employees;
183
184-- =============================================================================
185-- 6. νλ μ μ (Frame Specification)
186-- =============================================================================
187
188-- ROWS: 물리μ ν κΈ°μ€
189-- RANGE: λ
Όλ¦¬μ κ° κΈ°μ€
190
191-- νμ¬ ν κΈ°μ€ μλ€ 1ν
192SELECT
193 first_name,
194 salary,
195 AVG(salary) OVER(
196 ORDER BY salary
197 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
198 ) AS avg_neighbors
199FROM employees;
200
201-- μ²μλΆν° νμ¬ νκΉμ§
202SELECT
203 first_name,
204 salary,
205 MAX(salary) OVER(
206 ORDER BY emp_id
207 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
208 ) AS max_so_far
209FROM employees;
210
211-- νμ¬ νλΆν° λκΉμ§
212SELECT
213 first_name,
214 salary,
215 COUNT(*) OVER(
216 ORDER BY emp_id
217 ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
218 ) AS remaining_count
219FROM employees;
220
221-- =============================================================================
222-- 7. λ°±λΆμμμ λΆν¬ ν¨μ
223-- =============================================================================
224
225-- PERCENT_RANK: 0~1 μ¬μ΄μ μλμ μμ
226-- CUME_DIST: λμ λΆν¬
227
228SELECT
229 first_name,
230 salary,
231 ROUND(PERCENT_RANK() OVER(ORDER BY salary)::numeric, 4) AS pct_rank,
232 ROUND(CUME_DIST() OVER(ORDER BY salary)::numeric, 4) AS cumulative_dist
233FROM employees;
234
235-- λΆμ λ΄ λ°±λΆμ
236SELECT
237 e.first_name,
238 d.dept_name,
239 e.salary,
240 ROUND(PERCENT_RANK() OVER(
241 PARTITION BY e.dept_id ORDER BY e.salary
242 )::numeric, 4) AS dept_percentile
243FROM employees e
244JOIN departments d ON e.dept_id = d.dept_id;
245
246-- =============================================================================
247-- 8. μ€μ μμ
248-- =============================================================================
249
250-- κΈμ¬ ν΅κ³ μ’
ν©
251SELECT
252 e.first_name,
253 e.last_name,
254 d.dept_name,
255 e.salary,
256 -- λΆμ ν΅κ³
257 ROUND(AVG(e.salary) OVER(PARTITION BY e.dept_id), 2) AS dept_avg,
258 MIN(e.salary) OVER(PARTITION BY e.dept_id) AS dept_min,
259 MAX(e.salary) OVER(PARTITION BY e.dept_id) AS dept_max,
260 -- μ μ¬ ν΅κ³
261 ROUND(AVG(e.salary) OVER(), 2) AS company_avg,
262 -- μμ
263 RANK() OVER(PARTITION BY e.dept_id ORDER BY e.salary DESC) AS dept_rank,
264 RANK() OVER(ORDER BY e.salary DESC) AS company_rank,
265 -- μ μ¬ λλΉ λΉμ¨
266 ROUND(100.0 * e.salary / SUM(e.salary) OVER(), 2) AS company_pct
267FROM employees e
268JOIN departments d ON e.dept_id = d.dept_id
269ORDER BY d.dept_name, e.salary DESC;
270
271-- μ°μ κ³ μ© λΆμ (μ
μ¬μΌ κΈ°μ€ κ°κ²©)
272SELECT
273 first_name,
274 hire_date,
275 LAG(hire_date) OVER(ORDER BY hire_date) AS prev_hire_date,
276 hire_date - LAG(hire_date) OVER(ORDER BY hire_date) AS days_since_last_hire
277FROM employees
278ORDER BY hire_date;
279
280-- κΈμ¬ λμ λΆλ₯
281SELECT
282 first_name,
283 salary,
284 CASE NTILE(3) OVER(ORDER BY salary)
285 WHEN 1 THEN 'Low'
286 WHEN 2 THEN 'Medium'
287 WHEN 3 THEN 'High'
288 END AS salary_band
289FROM employees;
290
291-- =============================================================================
292-- 9. μλμ° ν¨μ λ³μΉ (WINDOW μ )
293-- =============================================================================
294
295-- κ°μ μλμ° μ μ μ¬μ¬μ©
296SELECT
297 first_name,
298 salary,
299 SUM(salary) OVER w AS running_total,
300 AVG(salary) OVER w AS running_avg,
301 COUNT(*) OVER w AS running_count
302FROM employees
303WINDOW w AS (ORDER BY emp_id)
304ORDER BY emp_id;
305
306-- =============================================================================
307-- μλμ° ν¨μ μμ½
308-- =============================================================================
309/*
310μμ ν¨μ:
311- ROW_NUMBER(): μ°μ λ²νΈ
312- RANK(): λμ μ κ°μ μμ, 건λλ
313- DENSE_RANK(): λμ μ κ°μ μμ, μ°μ
314- NTILE(n): nκ° λ²ν·μΌλ‘ λΆν
315
316μ€νμ
ν¨μ:
317- LAG(col, n, default): nν μ΄μ κ°
318- LEAD(col, n, default): nν μ΄ν κ°
319- FIRST_VALUE(col): νλ μμ 첫 κ°
320- LAST_VALUE(col): νλ μμ λ§μ§λ§ κ°
321- NTH_VALUE(col, n): νλ μμ nλ²μ§Έ κ°
322
323μ§κ³ ν¨μ:
324- SUM(), AVG(), COUNT(), MIN(), MAX() - OVER()μ ν¨κ»
325
326λΆν¬ ν¨μ:
327- PERCENT_RANK(): λ°±λΆμ¨ μμ (0~1)
328- CUME_DIST(): λμ λΆν¬
329
330νλ μ μ :
331- ROWS BETWEEN ... AND ...
332- RANGE BETWEEN ... AND ...
333- UNBOUNDED PRECEDING / FOLLOWING
334- CURRENT ROW
335- n PRECEDING / FOLLOWING
336
337ꡬ문:
338window_function() OVER(
339 [PARTITION BY col, ...]
340 [ORDER BY col [ASC|DESC], ...]
341 [frame_clause]
342)
343*/