1-- =============================================================================
2-- PostgreSQL ์๋ธ์ฟผ๋ฆฌ์ CTE ์์
3-- Subqueries and Common Table Expressions (CTE)
4-- =============================================================================
5
6-- ๋จผ์ ์ด์ ์์ ํ์ผ๋ค์ ์คํํ์ฌ ํ
์ด๋ธ๊ณผ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ์ธ์.
7
8-- =============================================================================
9-- 1. ์ค์นผ๋ผ ์๋ธ์ฟผ๋ฆฌ (๋จ์ผ ๊ฐ ๋ฐํ)
10-- =============================================================================
11
12-- SELECT ์ ์์ ์ฌ์ฉ
13SELECT
14 first_name,
15 last_name,
16 salary,
17 (SELECT AVG(salary) FROM employees) AS company_avg,
18 salary - (SELECT AVG(salary) FROM employees) AS diff_from_avg
19FROM employees;
20
21-- WHERE ์ ์์ ์ฌ์ฉ
22SELECT first_name, last_name, salary
23FROM employees
24WHERE salary > (SELECT AVG(salary) FROM employees);
25
26-- ๋ถ์๋ณ ํ๊ท ๋ณด๋ค ๋์ ๊ธ์ฌ๋ฅผ ๋ฐ๋ ์ง์
27SELECT e.first_name, e.last_name, e.salary, d.dept_name
28FROM employees e
29JOIN departments d ON e.dept_id = d.dept_id
30WHERE e.salary > (
31 SELECT AVG(salary)
32 FROM employees
33 WHERE dept_id = e.dept_id
34);
35
36-- =============================================================================
37-- 2. ์ธ๋ผ์ธ ๋ทฐ (FROM ์ ์๋ธ์ฟผ๋ฆฌ)
38-- =============================================================================
39
40-- ๋ถ์๋ณ ํต๊ณ๋ฅผ ์๋ธ์ฟผ๋ฆฌ๋ก ๊ตฌํ ํ ์กฐ์ธ
41SELECT
42 d.dept_name,
43 ds.employee_count,
44 ds.avg_salary,
45 ds.total_salary
46FROM departments d
47JOIN (
48 SELECT
49 dept_id,
50 COUNT(*) AS employee_count,
51 ROUND(AVG(salary), 2) AS avg_salary,
52 SUM(salary) AS total_salary
53 FROM employees
54 WHERE dept_id IS NOT NULL
55 GROUP BY dept_id
56) ds ON d.dept_id = ds.dept_id;
57
58-- ๊ธ์ฌ ์์์ ํจ๊ป ์กฐํ
59SELECT *
60FROM (
61 SELECT
62 first_name,
63 last_name,
64 salary,
65 RANK() OVER (ORDER BY salary DESC) AS salary_rank
66 FROM employees
67) ranked
68WHERE salary_rank <= 5;
69
70-- =============================================================================
71-- 3. EXISTS / NOT EXISTS
72-- =============================================================================
73
74-- ํ๋ก์ ํธ์ ์ฐธ์ฌ ์ค์ธ ์ง์
75SELECT e.first_name, e.last_name
76FROM employees e
77WHERE EXISTS (
78 SELECT 1
79 FROM employee_projects ep
80 WHERE ep.emp_id = e.emp_id
81);
82
83-- ํ๋ก์ ํธ์ ์ฐธ์ฌํ์ง ์๋ ์ง์
84SELECT e.first_name, e.last_name
85FROM employees e
86WHERE NOT EXISTS (
87 SELECT 1
88 FROM employee_projects ep
89 WHERE ep.emp_id = e.emp_id
90);
91
92-- ์ง์์ด ์๋ ๋ถ์
93SELECT d.dept_name
94FROM departments d
95WHERE EXISTS (
96 SELECT 1
97 FROM employees e
98 WHERE e.dept_id = d.dept_id
99);
100
101-- =============================================================================
102-- 4. IN / NOT IN
103-- =============================================================================
104
105-- Engineering ๋ถ์ ์ง์
106SELECT first_name, last_name
107FROM employees
108WHERE dept_id IN (
109 SELECT dept_id
110 FROM departments
111 WHERE dept_name = 'Engineering'
112);
113
114-- ํ๋ก์ ํธ์ ์ฐธ์ฌํ์ง ์๋ ์ง์ (NOT IN ์ฃผ์: NULL ์ฒ๋ฆฌ)
115SELECT first_name, last_name
116FROM employees
117WHERE emp_id NOT IN (
118 SELECT emp_id FROM employee_projects
119);
120
121-- =============================================================================
122-- 5. ANY / ALL
123-- =============================================================================
124
125-- Engineering ๋ถ์์ ์ด๋ค ์ง์๋ณด๋ค ๊ธ์ฌ๊ฐ ๋์ ์ง์
126SELECT first_name, last_name, salary
127FROM employees
128WHERE salary > ANY (
129 SELECT salary
130 FROM employees e
131 JOIN departments d ON e.dept_id = d.dept_id
132 WHERE d.dept_name = 'Engineering'
133);
134
135-- Engineering ๋ถ์์ ๋ชจ๋ ์ง์๋ณด๋ค ๊ธ์ฌ๊ฐ ๋์ ์ง์
136SELECT first_name, last_name, salary
137FROM employees
138WHERE salary > ALL (
139 SELECT salary
140 FROM employees e
141 JOIN departments d ON e.dept_id = d.dept_id
142 WHERE d.dept_name = 'Engineering'
143);
144
145-- =============================================================================
146-- 6. ์๊ด ์๋ธ์ฟผ๋ฆฌ (Correlated Subquery)
147-- =============================================================================
148
149-- ๊ฐ ์ง์์ ๋ถ์ ํ๊ท ๊ณผ ๋น๊ต
150SELECT
151 e.first_name,
152 e.last_name,
153 e.salary,
154 (
155 SELECT ROUND(AVG(e2.salary), 2)
156 FROM employees e2
157 WHERE e2.dept_id = e.dept_id
158 ) AS dept_avg_salary
159FROM employees e
160WHERE e.dept_id IS NOT NULL;
161
162-- ๋ถ์ ๋ด์์ ๊ฐ์ฅ ๋์ ๊ธ์ฌ๋ฅผ ๋ฐ๋ ์ง์
163SELECT e.first_name, e.last_name, e.salary, d.dept_name
164FROM employees e
165JOIN departments d ON e.dept_id = d.dept_id
166WHERE e.salary = (
167 SELECT MAX(e2.salary)
168 FROM employees e2
169 WHERE e2.dept_id = e.dept_id
170);
171
172-- =============================================================================
173-- 7. CTE (Common Table Expression) - WITH ์
174-- =============================================================================
175
176-- ๊ธฐ๋ณธ CTE
177WITH dept_stats AS (
178 SELECT
179 dept_id,
180 COUNT(*) AS employee_count,
181 ROUND(AVG(salary), 2) AS avg_salary,
182 SUM(salary) AS total_salary
183 FROM employees
184 WHERE dept_id IS NOT NULL
185 GROUP BY dept_id
186)
187SELECT
188 d.dept_name,
189 ds.employee_count,
190 ds.avg_salary,
191 ds.total_salary
192FROM departments d
193JOIN dept_stats ds ON d.dept_id = ds.dept_id
194ORDER BY ds.total_salary DESC;
195
196-- ์ฌ๋ฌ CTE ์ฌ์ฉ
197WITH
198high_earners AS (
199 SELECT emp_id, first_name, last_name, salary
200 FROM employees
201 WHERE salary > 50000
202),
203dept_names AS (
204 SELECT e.emp_id, d.dept_name
205 FROM employees e
206 JOIN departments d ON e.dept_id = d.dept_id
207)
208SELECT
209 h.first_name,
210 h.last_name,
211 h.salary,
212 dn.dept_name
213FROM high_earners h
214LEFT JOIN dept_names dn ON h.emp_id = dn.emp_id;
215
216-- CTE๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฐธ์กฐ
217WITH emp_summary AS (
218 SELECT
219 dept_id,
220 COUNT(*) AS emp_count,
221 AVG(salary) AS avg_salary
222 FROM employees
223 GROUP BY dept_id
224)
225SELECT
226 'Total Departments' AS metric,
227 COUNT(*) AS value
228FROM emp_summary
229UNION ALL
230SELECT
231 'Avg Employees per Dept',
232 ROUND(AVG(emp_count), 2)
233FROM emp_summary
234UNION ALL
235SELECT
236 'Overall Avg Salary',
237 ROUND(AVG(avg_salary), 2)
238FROM emp_summary;
239
240-- =============================================================================
241-- 8. ์ฌ๊ท CTE (Recursive CTE)
242-- =============================================================================
243
244-- ์ซ์ ์ํ์ค ์์ฑ
245WITH RECURSIVE numbers AS (
246 -- Base case
247 SELECT 1 AS n
248 UNION ALL
249 -- Recursive case
250 SELECT n + 1
251 FROM numbers
252 WHERE n < 10
253)
254SELECT n FROM numbers;
255
256-- ์กฐ์ง๋ (์ง์-๊ด๋ฆฌ์ ๊ณ์ธต)
257WITH RECURSIVE org_chart AS (
258 -- Base case: ์ต์์ ๊ด๋ฆฌ์ (manager_id๊ฐ NULL)
259 SELECT
260 emp_id,
261 first_name || ' ' || last_name AS name,
262 manager_id,
263 1 AS level,
264 ARRAY[emp_id] AS path
265 FROM employees
266 WHERE manager_id IS NULL
267
268 UNION ALL
269
270 -- Recursive case: ๋ถํ ์ง์
271 SELECT
272 e.emp_id,
273 e.first_name || ' ' || e.last_name,
274 e.manager_id,
275 oc.level + 1,
276 oc.path || e.emp_id
277 FROM employees e
278 JOIN org_chart oc ON e.manager_id = oc.emp_id
279)
280SELECT
281 REPEAT(' ', level - 1) || name AS employee_hierarchy,
282 level
283FROM org_chart
284ORDER BY path;
285
286-- ๋ ์ง ์๋ฆฌ์ฆ ์์ฑ
287WITH RECURSIVE date_series AS (
288 SELECT DATE '2024-01-01' AS date
289 UNION ALL
290 SELECT date + INTERVAL '1 day'
291 FROM date_series
292 WHERE date < DATE '2024-01-10'
293)
294SELECT date FROM date_series;
295
296-- =============================================================================
297-- 9. LATERAL JOIN (์๊ด ์๋ธ์ฟผ๋ฆฌ์ ๋์)
298-- =============================================================================
299
300-- ๊ฐ ๋ถ์์ ์์ 2๋ช
301SELECT d.dept_name, top_employees.*
302FROM departments d
303CROSS JOIN LATERAL (
304 SELECT first_name, last_name, salary
305 FROM employees e
306 WHERE e.dept_id = d.dept_id
307 ORDER BY salary DESC
308 LIMIT 2
309) AS top_employees;
310
311-- =============================================================================
312-- 10. ์๋ธ์ฟผ๋ฆฌ vs CTE vs LATERAL ๋น๊ต
313-- =============================================================================
314
315-- ๋ฐฉ๋ฒ 1: ์๋ธ์ฟผ๋ฆฌ (์ธ๋ผ์ธ ๋ทฐ)
316SELECT *
317FROM (
318 SELECT dept_id, AVG(salary) AS avg_sal
319 FROM employees
320 GROUP BY dept_id
321) sub
322WHERE avg_sal > 50000;
323
324-- ๋ฐฉ๋ฒ 2: CTE (๋ ์ฝ๊ธฐ ์ฌ์)
325WITH dept_avg AS (
326 SELECT dept_id, AVG(salary) AS avg_sal
327 FROM employees
328 GROUP BY dept_id
329)
330SELECT * FROM dept_avg WHERE avg_sal > 50000;
331
332-- ๋ฐฉ๋ฒ 3: LATERAL (ํ๋ณ๋ก ์๋ธ์ฟผ๋ฆฌ ํ์ํ ๋)
333SELECT d.dept_name, stats.avg_salary
334FROM departments d
335CROSS JOIN LATERAL (
336 SELECT ROUND(AVG(salary), 2) AS avg_salary
337 FROM employees e
338 WHERE e.dept_id = d.dept_id
339) stats
340WHERE stats.avg_salary > 50000;
341
342-- =============================================================================
343-- ์๋ธ์ฟผ๋ฆฌ์ CTE ์์ฝ
344-- =============================================================================
345/*
346์๋ธ์ฟผ๋ฆฌ ์์น:
347- SELECT: ์ค์นผ๋ผ ์๋ธ์ฟผ๋ฆฌ (๋จ์ผ ๊ฐ)
348- FROM: ์ธ๋ผ์ธ ๋ทฐ (ํ
์ด๋ธ์ฒ๋ผ ์ฌ์ฉ)
349- WHERE: ์กฐ๊ฑด์์ ์ฌ์ฉ
350
351์๋ธ์ฟผ๋ฆฌ ์ฐ์ฐ์:
352- =, <, >: ์ค์นผ๋ผ ๋น๊ต
353- IN, NOT IN: ๋ชฉ๋ก ํฌํจ ์ฌ๋ถ
354- EXISTS, NOT EXISTS: ์กด์ฌ ์ฌ๋ถ
355- ANY, ALL: ์กฐ๊ฑด ๋น๊ต
356
357CTE ์ฅ์ :
358- ๊ฐ๋
์ฑ ํฅ์
359- ์ฌ์ฌ์ฉ ๊ฐ๋ฅ
360- ์ฌ๊ท ์ฟผ๋ฆฌ ์ง์
361- ์คํ ๊ณํ ์ต์ ํ ํํธ (MATERIALIZED)
362
363LATERAL:
364- ํ๋ณ๋ก ์๊ด ์๋ธ์ฟผ๋ฆฌ ์คํ
365- TOP-N ๋ฌธ์ ์ ์ ์ฉ
366*/