-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChapter 3 - Subqueries & CTE.sql
More file actions
347 lines (253 loc) · 10.3 KB
/
Copy pathChapter 3 - Subqueries & CTE.sql
File metadata and controls
347 lines (253 loc) · 10.3 KB
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
-- Connect to database (MySQL)
USE maven_advanced_sql;
-- 1. Subqueries in the SELECT clause
SELECT * FROM happiness_scores;
-- Average happiness score
SELECT AVG(happiness_score) FROM happiness_scores;
-- Happiness score deviation from the average
SELECT year, country, happiness_score,
(SELECT AVG(happiness_score) FROM happiness_scores) as avg_hs,
happiness_score - (SELECT AVG(happiness_score) FROM happiness_scores) AS avg_diff
FROM happiness_scores;
-- 2. Subqueries in the FROM clause
SELECT * FROM happiness_scores;
-- Average happiness score for each country
SELECT country, AVG(happiness_score) AS avg_hs_country
FROM happiness_scores
GROUP BY country;
/* Return a country's happiness score for the year as well as
the average happiness score for the country across years */
SELECT hs.year, hs.country, hs.happiness_score, country_hs.avg_hs_country
FROM happiness_scores hs LEFT JOIN
(SELECT country, AVG(happiness_score) AS avg_hs_country
FROM happiness_scores
GROUP BY country) AS country_hs
ON hs.country = country_hs.country;
-- View one country
SELECT hs.year, hs.country, hs.happiness_score, country_hs.avg_hs_country
FROM happiness_scores hs LEFT JOIN
(SELECT country, AVG(happiness_score) AS avg_hs_country
FROM happiness_scores
GROUP BY country) AS country_hs
ON hs.country = country_hs.country
WHERE hs.country = 'India';
-- 3. Multiple subqueries
SELECT * FROM happiness_scores;
SELECT * FROM happiness_scores_current;
-- Return happiness scores for 2015 - 2024
SELECT year, country, happiness_score FROM happiness_scores
UNION ALL SELECT 2024, country, ladder_score FROM happiness_scores_current;
/* Return a country's happiness score for the year as well as
the average happiness score for the country across years */
SELECT hs.year, hs.country, hs.happiness_score, country_hs.avg_hs_country
FROM (SELECT year, country, happiness_score FROM happiness_scores
UNION ALL
SELECT 2024, country, ladder_score FROM happiness_scores_current) as hs
LEFT JOIN
(SELECT country, AVG(happiness_score) AS avg_hs_country
FROM happiness_scores
GROUP BY country) AS country_hs
ON hs.country = country_hs.country
ORDER BY hs.year DESC;
/* Return years where the happiness score is a whole point
greater than the country's average happiness score */
SELECT * FROM
(SELECT hs.year, hs.country, hs.happiness_score, country_hs.avg_hs_country
FROM (SELECT year, country, happiness_score FROM happiness_scores
UNION ALL
SELECT 2024, country, ladder_score FROM happiness_scores_current) as hs
LEFT JOIN
(SELECT country, AVG(happiness_score) AS avg_hs_country
FROM happiness_scores
GROUP BY country) AS country_hs
ON hs.country = country_hs.country) AS hs_country_hs
WHERE happiness_score > avg_hs_country +1;
-- 4. Subqueries in the WHERE and HAVING clauses
SELECT * FROM happiness_scores;
-- Average happiness score
SELECT AVG(happiness_score) FROM happiness_scores;
-- Above average happiness scores (WHERE)
SELECT *
FROM happiness_scores
WHERE happiness_score > (SELECT AVG(happiness_score) FROM happiness_scores);
-- Above average happiness scores for each region (HAVING)
SELECT region, AVG(happiness_score) as avg_hs
FROM happiness_scores
GROUP BY region
HAVING avg_hs > (SELECT AVG(happiness_score) FROM happiness_scores);
-- 5. ANY vs ALL
SELECT MAX(ladder_score)
FROM happiness_scores_current;
-- Scores that are greater than ANY 2024 scores
SELECT year, country, region, happiness_score
FROM happiness_scores
WHERE happiness_score >
ANY (SELECT ladder_score
FROM happiness_scores_current)
ORDER BY happiness_score;
-- Scores that are greater than ALL 2024 scores
SELECT *
FROM happiness_scores
WHERE happiness_score >
ALL (SELECT ladder_score
FROM happiness_scores_current);
-- 6. EXISTS
SELECT * FROM inflation_rates;
/* Return happiness scores of countries
that exist in the inflation rates table */
SELECT h.year, h.country, h.happiness_score
FROM happiness_scores h
WHERE EXISTS ( SELECT i.country_name FROM inflation_rates i WHERE i.country_name = h.country);
-- Alternative to EXISTS: INNER JOIN
SELECT h.year, h.country, h.happiness_score, i.inflation_rate
FROM happiness_scores h
INNER JOIN inflation_rates i
ON h.country = i.country_name
AND h.year = i.year;
-- 7. CTEs: Readability
SELECT AVG(happiness_score) AS avg_hs, country FROM happiness_scores GROUP BY country;
/* SUBQUERY: Return the happiness scores along with
the average happiness score for each country */
SELECT hs.year, hs.country, hs.happiness_score, country_hs.avg_hs
FROM happiness_scores hs LEFT JOIN
(SELECT AVG(happiness_score) AS avg_hs, country FROM happiness_scores GROUP BY country) AS country_hs
ON hs.country = country_hs.country;
/* CTE: Return the happiness scores along with
the average happiness score for each country */
WITH country_hs AS (SELECT AVG(happiness_score) AS avg_hs, country FROM happiness_scores GROUP BY country)
SELECT hs.year,hs.country, hs.happiness_score, country_hs.avg_hs
FROM happiness_scores hs
LEFT JOIN country_hs
ON hs.country = country_hs.country;
-- 8. CTEs: Reusability
SELECT * FROM happiness_scores WHERE year = 2023 ;
-- SUBQUERY: Compare the happiness scores within each region in 2023
SELECT hs1.region, hs1.country, hs1.happiness_score,
hs2.region, hs2.happiness_score
FROM
(SELECT * FROM happiness_scores WHERE year = 2023) AS hs1
INNER JOIN
(SELECT * FROM happiness_scores WHERE year = 2023) AS hs2
ON hs1.region = hs2.region
WHERE hs1.happiness_score > hs2.happiness_score;
-- CTE: Compare the happiness scores within each region in 2023
WITH hs AS (SELECT * FROM happiness_scores WHERE year = 2023)
SELECT hs1.region, hs1.country, hs1.happiness_score,
hs2.region, hs2.happiness_score
FROM hs hs1 INNER JOIN hs hs2
ON hs1.region = hs2.region
WHERE hs1.country > hs2.country;
-- 9. Multiple CTEs
SELECT * FROM happiness_scores WHERE year = 2023;
SELECT * FROM happiness_scores_current;
-- Step 1: Compare 2023 vs 2024 happiness scores side by side
WITH hs23 AS (SELECT * FROM happiness_scores WHERE year = 2023),
hs24 AS (SELECT * FROM happiness_scores_current)
SELECT hs23.country, hs23.happiness_score AS hs_2023,
hs24.ladder_score AS hs_2024
FROM hs23 LEFT JOIN hs24
ON hs23.country = hs24.country;
-- Step 2: Return the countries where the score increased
SELECT *
FROM (WITH hs23 AS (SELECT * FROM happiness_scores WHERE year = 2023),
hs24 AS (SELECT * FROM happiness_scores_current)
SELECT hs23.country, hs23.happiness_score AS hs_2023,
hs24.ladder_score AS hs_2024
FROM hs23 LEFT JOIN hs24
ON hs23.country = hs24.country) AS hs_23_24
WHERE hs_2024 > hs_2023;
-- Alternative: CTEs only
WITH hs23 AS (SELECT * FROM happiness_scores WHERE year = 2023),
hs24 AS (SELECT * FROM happiness_scores_current),
hs_23_24 AS (SELECT hs23.country, hs23.happiness_score AS hs_2023,
hs24.ladder_score AS hs_2024
FROM hs23 LEFT JOIN hs24
ON hs23.country = hs24.country)
SELECT *
FROM hs_23_24
WHERE hs_2024 > hs_2023;
-- 10. Recursive CTEs
-- Create a stock prices table
CREATE TABLE IF NOT EXISTS stock_prices (
date DATE PRIMARY KEY,
price DECIMAL(10, 2)
);
INSERT INTO stock_prices (date, price) VALUES
('2024-11-01', 678.27),
('2024-11-03', 688.83),
('2024-11-04', 645.40),
('2024-11-06', 591.01);
SELECT * FROM stock_prices;
/* Employee table was created in prior section:
This is the code if you need to create it again */
/*
CREATE TABLE IF NOT EXISTS employees (
employee_id INT PRIMARY KEY,
employee_name VARCHAR(100),
salary INT,
manager_id INT
);
INSERT INTO employees (employee_id, employee_name, salary, manager_id) VALUES
(1, 'Ava', 85000, NULL),
(2, 'Bob', 72000, 1),
(3, 'Cat', 59000, 1),
(4, 'Dan', 85000, 2);
*/
-- Example 1: Generating sequences
-- Generate a column of dates
WITH RECURSIVE my_dates(dt) AS
(SELECT '2024-11-01'
UNION ALL
SELECT dt + INTERVAL 1 DAY
FROM my_dates
WHERE dt < '2024-11-06')
SELECT * FROM my_dates;
-- Include the original prices
WITH RECURSIVE my_dates(dt) AS
(SELECT '2024-11-01'
UNION ALL
SELECT dt + INTERVAL 1 DAY
FROM my_dates
WHERE dt < '2024-11-06')
SELECT md.dt, sp.price
FROM my_dates md
LEFT JOIN stock_prices sp
ON md.dt = sp.date;
-- Example 2: Working with hierachical data
SELECT * FROM EMPLOYEES;
-- Return the reporting chain for each employee
WITH recursive employee_hierarchy AS ( SELECT employee_id, employee_name, manager_id, employee_name AS hierarchy
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.employee_name, e.manager_id, CONCAT(eh.hierarchy, ' > ', e.employee_name) AS hierarchy
FROM employees e INNER JOIN employee_hierarchy eh
ON e.manager_id = eh.employee_id )
SELECT employee_id, employee_name, manager_id, hierarchy
FROM employee_hierarchy
ORDER BY employee_id;
-- 11. Subquery vs CTE vs Temp Table vs View
-- 1. Both Subquery and CTE only exist for the duration of the query
-- Subquery
SELECT *
FROM ( SELECT year, country, happiness_score FROM happiness_scores
UNION ALL
SELECT 2024, country, ladder_score FROM happiness_scores_current ) AS my_subquery;
-- CTE
WITH my_cte AS ( SELECT year, country, happiness_score FROM happiness_scores
UNION ALL
SELECT 2024, country, ladder_score FROM happiness_scores_current )
SELECT * FROM my_cte;
-- 2. Temporary tables exist for a session [ i.e until you close your sql window ] and Vies continue to exist until modified or dropped
--- Temporary table
CREATE TEMPORARY TABLE my_temp_table AS
SELECT year, country, happiness_score FROM happiness_scores
UNION ALL
SELECT 2024, country, ladder_score FROM happiness_scores_current;
SELECT * FROM my_temp_table;
-- View
CREATE VIEW my_view AS
SELECT year, country, happiness_score FROM happiness_scores
UNION ALL
SELECT 2024, country, ladder_score FROM happiness_scores_current;
SELECT * FROM my_view;