@@ -12,6 +12,7 @@ JOIN departments d ON d.dept_no = de.dept_no
1212GROUP BY d .dept_no
1313ORDER BY 1 ;
1414
15+ /* ------------------------------------------------------------------------------------------------------------*/
1516
1617/* *********** 2) HAVING Keyword *************/
1718/*
@@ -45,6 +46,7 @@ GROUP BY d.dept_name
4546HAVING COUNT (e .emp_no ) > 25000
4647ORDER BY 1 ;
4748
49+ /* ------------------------------------------------------------------------------------------------------------*/
4850
4951/* ********* 3) Ordering Group Data **********/
5052SELECT d .dept_name AS " Department Name" ,COUNT (e .emp_no ) AS " Number Of Employee"
@@ -56,13 +58,17 @@ HAVING COUNT(e.emp_no) > 25000
5658ORDER BY 2 DESC ;
5759
5860
59- /* ******** 4) Group by Mental Model ***********/
61+ /* ******** 4) GROUP BY Mental Model ***********/
62+
6063/* What are the 8 employees who got the most salary bumps? */
6164-- SELECT e.emp_no, CONCAT(e.first_name, e.last_name) AS "Name", s.salary, s.from_date, s.to_date
6265SELECT emp_no, MAX (from_date)
6366FROM salaries
6467GROUP BY emp_no;
6568
69+
70+ /* ------------------------------------------------------------------------------------------------------------*/
71+
6672/* ********** 5) GROUPING SETS**********/
6773
6874/* ****** UNION / UNION ALL *********/
@@ -81,20 +87,25 @@ GROUP BY emp_no;
8187*/
8288SELECT NULL AS " prod_id" , sum (ol .quantity )
8389FROM orderlines AS ol
90+
8491UNION
92+
8593SELECT prod_id AS " prod_id" , sum (ol .quantity )
8694FROM orderlines AS ol
8795GROUP BY prod_id
8896ORDER BY prod_id DESC ;
8997
98+ /* ------------------------------------------------------------------------------------------------------------*/
99+
90100/* ********** GROUPING SETS ***********/
91101/*
92102 A Subclause of GROUP BY that allows you to define multiple grouping
93103 It is very useful when we want to combine multiple grouping
94104*/
95105
96- -- same result as using above UNION code
97- SELECT NULL AS " prod_id" , sum (ol .quantity )
106+ -- same result as using above UNION code, but in same query
107+ -- here we are combining Two Sets (one for getting Total, one for per each product)
108+ SELECT prod_id, sum (ol .quantity )
98109FROM orderlines AS ol
99110GROUP BY
100111 GROUPING SETS(
@@ -103,13 +114,213 @@ GROUP BY
103114 )
104115ORDER BY prod_id DESC ;
105116
117+
106118/* we can add in multiple groups as we need */
107- SELECT NULL AS " prod_id" , orderlineid, sum (ol .quantity )
119+ SELECT prod_id, orderlineid, sum (ol .quantity )
108120FROM orderlines AS ol
109121GROUP BY
110122 GROUPING SETS(
111123 (),
112124 (prod_id),
113125 (orderlineid)
114126 )
115- ORDER BY prod_id DESC , orderlineid DESC ;
127+ ORDER BY prod_id DESC , orderlineid DESC ;
128+
129+ /* ------------------------------------------------------------------------------------------------------------*/
130+
131+ /* *********** GROUPING SETS for info from High Level to Details Level ***********/
132+
133+ SELECT
134+ EXTRACT(YEAR FROM orderdate) AS " YEAR" ,
135+ EXTRACT(MONTH FROM orderdate) AS " MONTH" ,
136+ EXTRACT(DAY FROM orderdate) AS " DAY" ,
137+ SUM (quantity)AS " TOTAL QUANTITY"
138+ FROM orderlines
139+ GROUP BY
140+ GROUPING SETS(
141+ (EXTRACT(YEAR FROM orderdate)), -- yearly
142+ (EXTRACT(MONTH FROM orderdate)), -- monthly
143+ (EXTRACT(DAY FROM orderdate)), -- daily
144+ (
145+ EXTRACT(YEAR FROM orderdate), -- month and year
146+ EXTRACT(MONTH FROM orderdate)
147+ ),
148+ (
149+ EXTRACT(MONTH FROM orderdate), -- month and day
150+ EXTRACT(DAY FROM orderdate)
151+ ),
152+ (
153+ EXTRACT(YEAR FROM orderdate), -- year, month and day
154+ EXTRACT(MONTH FROM orderdate),
155+ EXTRACT(DAY FROM orderdate)
156+ ),
157+ () -- nothing in particular (TOTAL AMOUNT)
158+ )
159+ ORDER BY 1 ,2 ,3 ;
160+
161+ /* ------------------------------------------------------------------------------------------------------------*/
162+
163+ /* *********** 6) ROLLUP ***************/
164+
165+ /* roll up can provide a very similar result as above using grouping sets, but with less code */
166+ SELECT
167+ EXTRACT(YEAR FROM orderdate) AS " YEAR" ,
168+ EXTRACT(MONTH FROM orderdate) AS " MONTH" ,
169+ EXTRACT(DAY FROM orderdate) AS " DAY" ,
170+ SUM (quantity)AS " TOTAL QUANTITY"
171+ FROM orderlines
172+ GROUP BY
173+ ROLLUP(
174+ EXTRACT(YEAR FROM orderdate),
175+ EXTRACT(MONTH FROM orderdate),
176+ EXTRACT(DAY FROM orderdate)
177+ )
178+ ORDER BY 1 ,2 ,3 ;
179+
180+ /* ------------------------------------------------------------------------------------------------------------*/
181+
182+ /* ******************* 8/9) WINDOW Functions ******************/
183+ /*
184+ Window functions CREATE a NEW COLUMN based on functions performed on a SUBSET or "WINDOW" of the data.
185+
186+ window_function(agr1, agr2) OVER(
187+ [PARTITION BY partition_expression]
188+ [ORDER BY sort_expression [ASC | DESC] [NULLS {FIRST | LAST}]]
189+ )
190+ */
191+
192+ -- Here we can see in the result that max salary is 158,220. Because query returns all data, then LIMIT say cut it off for 100 rows only.
193+ -- That's why OVER() is calculated on the window or subset of data (in this case the entire data were returned).
194+ SELECT * ,
195+ MAX (salary) OVER()
196+ FROM salaries
197+ LIMIT 100 ;
198+
199+ -- in this case, the maximum salary is 69,999. Because of WHERE conditions, the data were filtered out.
200+ -- and OVER() is using on that subset or window of the returned data (in this case the results of WHERE filtered data).
201+ SELECT
202+ * ,
203+ MAX (salary) OVER()
204+ FROM salaries
205+ WHERE salary < 70000
206+ ORDER BY salary DESC ;
207+
208+
209+ /* ******************* 10) PARTITON BY ******************/
210+ /*
211+ Divide Rows into Groups to apply the function against (Optional)
212+ */
213+
214+ /* Employee salary compairing average salary of departments */
215+ SELECT
216+ s .emp_no , s .salary ,d .dept_name ,
217+ AVG (s .salary )
218+ OVER(
219+ PARTITION BY(d .dept_name )
220+ )
221+ FROM salaries s
222+ JOIN dept_emp de ON s .emp_no = de .emp_no
223+ JOIN departments d ON d .dept_no = de .dept_no ;
224+
225+
226+ /* ******************* 11) ORDER BY ******************/
227+ /*
228+ ORDER BY changes the FRAME of the window
229+ It tells SQL to take into account of everything before up until to this point (becoming Cumulative)
230+ */
231+ -- against the window of entire data
232+ SELECT emp_no,
233+ COUNT (salary) OVER()
234+ FROM salaries;
235+
236+ -- using PARTION BY
237+ -- Counting salary by each unique emp_no partion
238+ SELECT emp_no,
239+ COUNT (salary) OVER(
240+ PARTITION BY(emp_no)
241+ )
242+ FROM salaries;
243+
244+
245+ -- using ORDER BY
246+ -- Count number are becoming Cumulative
247+ SELECT emp_no,
248+ COUNT (salary) OVER(
249+ ORDER BY emp_no
250+ )
251+ FROM salaries;
252+
253+
254+ /* ******************************** FRAME Clause *******************************************************/
255+ /*
256+ When using Frame clause in a window function, we can create a SUB-RANGE or FRAME
257+
258+ For example: when we use ORDER BY, we look at the PARTATIONED data in a different len (FRAME).
259+
260+ NOTE:
261+ Without ORDER BY, by default the framing is usually ALL PARTITION ROWs (Entire Window)
262+ With ORDER BY, by default the framing is usually everything before the CURRENT ROW AND the CURRENT ROW (Cumulatively)
263+
264+ |----------------------------------------------------------------------------------------------------
265+ | Keys | Meaning |
266+ |---------------------------------------|-----------------------------------------------------------|
267+ | ROWS or RANGE | Whether you want to use a RANGE or ROWS as a FRAME |
268+ | PRECEDING | Rows Before the CURRENT ONE |
269+ | FOLLOWING | Rows After the CURRENT ONE |
270+ | UNBOUNDED PRECEDING or FOLLOWING | Returns All Before and After |
271+ | CURRENT ROW | Your Current Row |
272+ -----------------------------------------------------------------------------------------------------
273+ */
274+
275+ -- In this case, we can see that every salary is unique. Because we are using ORDER BY, each row is cumulativly
276+ -- counted within the partition of each employee's window. As a result, it like like 1, (1+1 becomes 2), etc.
277+ SELECT emp_no,
278+ salary,
279+ COUNT (salary) OVER(
280+ PARTITION BY emp_no
281+ ORDER BY salary
282+ )
283+ FROM Salaries;
284+
285+
286+ -- This one returns the same results as using PARTION BY only. The reason is we are looking at the data through the lends of Range.
287+ -- For range using unbounded precedning and following, we are comparing against data with the entire data within that Partition.
288+ SELECT emp_no,
289+ salary,
290+ COUNT (salary) OVER(
291+ PARTITION BY emp_no
292+ ORDER BY salary
293+ RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
294+ )
295+ FROM Salaries;
296+
297+ -- same reults as RANGE results
298+ SELECT emp_no,
299+ salary,
300+ COUNT (salary) OVER(
301+ PARTITION BY emp_no
302+ ORDER BY salary
303+ ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
304+ )
305+ FROM Salaries;
306+
307+
308+ -- same like ORDER BY
309+ SELECT emp_no,
310+ salary,
311+ COUNT (salary) OVER(
312+ PARTITION BY emp_no
313+ ORDER BY salary
314+ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
315+ )
316+ FROM Salaries;
317+
318+ /* ------------------------------------------------------------------------------------------------------------*/
319+
320+
321+
322+
323+
324+
325+
326+
0 commit comments