1-- =============================================================================
2-- PostgreSQL ์ง๊ณ ํจ์ ์์
3-- Aggregation Functions and GROUP BY
4-- =============================================================================
5
6-- ๋จผ์ 01_basic_crud.sql๊ณผ 02_joins.sql์ ์คํํ์ฌ ํ
์ด๋ธ๊ณผ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ์ธ์.
7
8-- =============================================================================
9-- 1. ๊ธฐ๋ณธ ์ง๊ณ ํจ์
10-- =============================================================================
11
12-- COUNT - ํ ๊ฐ์
13SELECT COUNT(*) AS total_employees FROM employees;
14
15SELECT COUNT(email) AS employees_with_email FROM employees; -- NULL ์ ์ธ
16
17SELECT COUNT(DISTINCT dept_id) AS unique_departments FROM employees;
18
19-- SUM - ํฉ๊ณ
20SELECT SUM(salary) AS total_salary FROM employees;
21
22-- AVG - ํ๊ท
23SELECT AVG(salary) AS average_salary FROM employees;
24
25SELECT ROUND(AVG(salary), 2) AS avg_salary_rounded FROM employees;
26
27-- MIN, MAX - ์ต์๊ฐ, ์ต๋๊ฐ
28SELECT
29 MIN(salary) AS min_salary,
30 MAX(salary) AS max_salary
31FROM employees;
32
33SELECT
34 MIN(hire_date) AS first_hire,
35 MAX(hire_date) AS last_hire
36FROM employees;
37
38-- ๋ชจ๋ ์ง๊ณ ํจ์ ํจ๊ป ์ฌ์ฉ
39SELECT
40 COUNT(*) AS employee_count,
41 SUM(salary) AS total_salary,
42 ROUND(AVG(salary), 2) AS avg_salary,
43 MIN(salary) AS min_salary,
44 MAX(salary) AS max_salary,
45 MAX(salary) - MIN(salary) AS salary_range
46FROM employees;
47
48-- =============================================================================
49-- 2. GROUP BY
50-- =============================================================================
51
52-- ๋ถ์๋ณ ์ง๊ณ
53SELECT
54 dept_id,
55 COUNT(*) AS employee_count,
56 ROUND(AVG(salary), 2) AS avg_salary
57FROM employees
58WHERE dept_id IS NOT NULL
59GROUP BY dept_id
60ORDER BY employee_count DESC;
61
62-- JOIN๊ณผ ํจ๊ป ์ฌ์ฉ
63SELECT
64 d.dept_name,
65 COUNT(e.emp_id) AS employee_count,
66 SUM(e.salary) AS total_salary,
67 ROUND(AVG(e.salary), 2) AS avg_salary
68FROM departments d
69LEFT JOIN employees e ON d.dept_id = e.dept_id
70GROUP BY d.dept_id, d.dept_name
71ORDER BY total_salary DESC NULLS LAST;
72
73-- ์ฌ๋ฌ ์ปฌ๋ผ์ผ๋ก ๊ทธ๋ฃนํ
74SELECT
75 dept_id,
76 is_active,
77 COUNT(*) AS employee_count
78FROM employees
79GROUP BY dept_id, is_active
80ORDER BY dept_id, is_active;
81
82-- ํํ์์ผ๋ก ๊ทธ๋ฃนํ
83SELECT
84 EXTRACT(YEAR FROM hire_date) AS hire_year,
85 COUNT(*) AS hire_count
86FROM employees
87GROUP BY EXTRACT(YEAR FROM hire_date)
88ORDER BY hire_year;
89
90-- =============================================================================
91-- 3. HAVING - ๊ทธ๋ฃน ํํฐ๋ง
92-- =============================================================================
93
94-- ์ง์์ด 2๋ช
์ด์์ธ ๋ถ์
95SELECT
96 d.dept_name,
97 COUNT(e.emp_id) AS employee_count
98FROM departments d
99JOIN employees e ON d.dept_id = e.dept_id
100GROUP BY d.dept_id, d.dept_name
101HAVING COUNT(e.emp_id) >= 2
102ORDER BY employee_count DESC;
103
104-- ํ๊ท ๊ธ์ฌ๊ฐ 50000 ์ด์์ธ ๋ถ์
105SELECT
106 d.dept_name,
107 ROUND(AVG(e.salary), 2) AS avg_salary
108FROM departments d
109JOIN employees e ON d.dept_id = e.dept_id
110GROUP BY d.dept_id, d.dept_name
111HAVING AVG(e.salary) >= 50000
112ORDER BY avg_salary DESC;
113
114-- WHERE์ HAVING ํจ๊ป ์ฌ์ฉ
115SELECT
116 d.dept_name,
117 COUNT(e.emp_id) AS employee_count,
118 ROUND(AVG(e.salary), 2) AS avg_salary
119FROM departments d
120JOIN employees e ON d.dept_id = e.dept_id
121WHERE e.is_active = TRUE -- ํ ํํฐ๋ง (๊ทธ๋ฃน ์ )
122GROUP BY d.dept_id, d.dept_name
123HAVING COUNT(e.emp_id) >= 1 -- ๊ทธ๋ฃน ํํฐ๋ง (๊ทธ๋ฃน ํ)
124ORDER BY avg_salary DESC;
125
126-- =============================================================================
127-- 4. ๊ณ ๊ธ ์ง๊ณ ํจ์
128-- =============================================================================
129
130-- STRING_AGG - ๋ฌธ์์ด ์ฐ๊ฒฐ
131SELECT
132 d.dept_name,
133 STRING_AGG(e.first_name || ' ' || e.last_name, ', ' ORDER BY e.first_name) AS employee_names
134FROM departments d
135JOIN employees e ON d.dept_id = e.dept_id
136GROUP BY d.dept_id, d.dept_name;
137
138-- ARRAY_AGG - ๋ฐฐ์ด๋ก ์ง๊ณ
139SELECT
140 d.dept_name,
141 ARRAY_AGG(e.first_name ORDER BY e.first_name) AS employee_names_array
142FROM departments d
143JOIN employees e ON d.dept_id = e.dept_id
144GROUP BY d.dept_id, d.dept_name;
145
146-- JSON_AGG - JSON ๋ฐฐ์ด๋ก ์ง๊ณ
147SELECT
148 d.dept_name,
149 JSON_AGG(
150 JSON_BUILD_OBJECT(
151 'name', e.first_name || ' ' || e.last_name,
152 'salary', e.salary
153 )
154 ) AS employees_json
155FROM departments d
156JOIN employees e ON d.dept_id = e.dept_id
157GROUP BY d.dept_id, d.dept_name;
158
159-- =============================================================================
160-- 5. ROLLUP, CUBE, GROUPING SETS
161-- =============================================================================
162
163-- ROLLUP - ๊ณ์ธต์ ์๊ณ
164SELECT
165 d.dept_name,
166 EXTRACT(YEAR FROM e.hire_date) AS hire_year,
167 COUNT(*) AS employee_count,
168 SUM(e.salary) AS total_salary
169FROM employees e
170JOIN departments d ON e.dept_id = d.dept_id
171GROUP BY ROLLUP(d.dept_name, EXTRACT(YEAR FROM e.hire_date))
172ORDER BY d.dept_name NULLS LAST, hire_year NULLS LAST;
173
174-- CUBE - ๋ชจ๋ ๊ฐ๋ฅํ ์กฐํฉ์ ์๊ณ
175SELECT
176 d.dept_name,
177 e.is_active,
178 COUNT(*) AS employee_count
179FROM employees e
180JOIN departments d ON e.dept_id = d.dept_id
181GROUP BY CUBE(d.dept_name, e.is_active)
182ORDER BY d.dept_name NULLS LAST, e.is_active NULLS LAST;
183
184-- GROUPING SETS - ํน์ ์กฐํฉ๋ง ์๊ณ
185SELECT
186 d.dept_name,
187 EXTRACT(YEAR FROM e.hire_date) AS hire_year,
188 COUNT(*) AS employee_count
189FROM employees e
190JOIN departments d ON e.dept_id = d.dept_id
191GROUP BY GROUPING SETS (
192 (d.dept_name),
193 (EXTRACT(YEAR FROM e.hire_date)),
194 ()
195)
196ORDER BY d.dept_name NULLS LAST, hire_year NULLS LAST;
197
198-- GROUPING() ํจ์๋ก ์๊ณ ํ ๊ตฌ๋ถ
199SELECT
200 CASE WHEN GROUPING(d.dept_name) = 1 THEN 'All Departments' ELSE d.dept_name END AS dept_name,
201 COUNT(*) AS employee_count,
202 SUM(e.salary) AS total_salary
203FROM employees e
204JOIN departments d ON e.dept_id = d.dept_id
205GROUP BY ROLLUP(d.dept_name)
206ORDER BY GROUPING(d.dept_name), d.dept_name;
207
208-- =============================================================================
209-- 6. FILTER ์
210-- =============================================================================
211
212-- ์กฐ๊ฑด๋ณ๋ก ๋ค๋ฅธ ์ง๊ณ
213SELECT
214 d.dept_name,
215 COUNT(*) AS total_count,
216 COUNT(*) FILTER (WHERE e.salary > 50000) AS high_salary_count,
217 COUNT(*) FILTER (WHERE e.salary <= 50000) AS low_salary_count,
218 ROUND(AVG(e.salary) FILTER (WHERE e.is_active = TRUE), 2) AS active_avg_salary
219FROM departments d
220JOIN employees e ON d.dept_id = e.dept_id
221GROUP BY d.dept_id, d.dept_name;
222
223-- =============================================================================
224-- 7. ํต๊ณ ํจ์
225-- =============================================================================
226
227-- ํ์คํธ์ฐจ์ ๋ถ์ฐ
228SELECT
229 d.dept_name,
230 ROUND(AVG(e.salary), 2) AS avg_salary,
231 ROUND(STDDEV(e.salary), 2) AS stddev_salary,
232 ROUND(VARIANCE(e.salary), 2) AS variance_salary
233FROM departments d
234JOIN employees e ON d.dept_id = e.dept_id
235GROUP BY d.dept_id, d.dept_name
236HAVING COUNT(*) > 1; -- ํ์คํธ์ฐจ๋ 2๊ฐ ์ด์ ํ์
237
238-- ๋ฐฑ๋ถ์์
239SELECT
240 PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) AS median_salary,
241 PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY salary) AS q1_salary,
242 PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY salary) AS q3_salary
243FROM employees;
244
245-- ์ต๋น๊ฐ (MODE)
246SELECT
247 MODE() WITHIN GROUP (ORDER BY dept_id) AS most_common_dept
248FROM employees;
249
250-- =============================================================================
251-- 8. ์กฐ๊ฑด๋ถ ์ง๊ณ (CASE์ ํจ๊ป)
252-- =============================================================================
253
254SELECT
255 d.dept_name,
256 COUNT(*) AS total,
257 SUM(CASE WHEN e.salary >= 55000 THEN 1 ELSE 0 END) AS high_earners,
258 SUM(CASE WHEN e.salary < 55000 THEN 1 ELSE 0 END) AS others,
259 ROUND(
260 100.0 * SUM(CASE WHEN e.salary >= 55000 THEN 1 ELSE 0 END) / COUNT(*),
261 1
262 ) AS high_earner_pct
263FROM departments d
264JOIN employees e ON d.dept_id = e.dept_id
265GROUP BY d.dept_id, d.dept_name;
266
267-- =============================================================================
268-- ์ง๊ณ ํจ์ ์์ฝ
269-- =============================================================================
270/*
271๊ธฐ๋ณธ ์ง๊ณ:
272- COUNT(*), COUNT(col), COUNT(DISTINCT col)
273- SUM(col), AVG(col)
274- MIN(col), MAX(col)
275
276๋ฌธ์์ด/๋ฐฐ์ด ์ง๊ณ:
277- STRING_AGG(col, delimiter)
278- ARRAY_AGG(col)
279- JSON_AGG(value)
280
281๊ทธ๋ฃนํ:
282- GROUP BY: ๊ธฐ๋ณธ ๊ทธ๋ฃนํ
283- HAVING: ๊ทธ๋ฃน ํํฐ๋ง (์ง๊ณ ํ)
284- ROLLUP: ๊ณ์ธต์ ์๊ณ
285- CUBE: ๋ชจ๋ ์กฐํฉ ์๊ณ
286- GROUPING SETS: ํน์ ์กฐํฉ ์๊ณ
287
288๊ณ ๊ธ:
289- FILTER (WHERE ...): ์กฐ๊ฑด๋ถ ์ง๊ณ
290- PERCENTILE_CONT(): ๋ฐฑ๋ถ์์
291- STDDEV(), VARIANCE(): ํต๊ณ
292
293์์:
294SELECT โ FROM โ WHERE โ GROUP BY โ HAVING โ ORDER BY โ LIMIT
295*/