SQL Advanced in MS SQL: Difference between revisions
Jump to navigation
Jump to search
Lsokolowski1 (talk | contribs) m (→Grouping sets) |
Lsokolowski1 (talk | contribs) m (→Exercises) |
||
(25 intermediate revisions by the same user not shown) | |||
Line 941: | Line 941: | ||
* CASE expression | * CASE expression | ||
* Grouping sets | * Grouping sets | ||
* Hierarchical queries | |||
* Analytic functions | |||
* Insert | * Insert | ||
* Delete | * Delete | ||
Line 1,014: | Line 1,016: | ||
-- ename LIKE '%l%' AND ename LIKE '%n%' AND ename LIKE '%w%' | -- ename LIKE '%l%' AND ename LIKE '%n%' AND ename LIKE '%w%' | ||
---- Search for people hired not in months: '''Jan''' and '''Dec''' | ---- Search for people hired not in months: '''Jan''' and '''Dec''' | ||
-- hiredate LIKE '% | -- convert(varchar, hiredate, 104) LIKE '%.0[^1].%' OR convert(varchar, hiredate, 104) LIKE '%.1[^2].%' | ||
ORDER BY 2 | ORDER BY 2 | ||
; | ; | ||
Line 1,094: | Line 1,096: | ||
(deptno, job, grade), | (deptno, job, grade), | ||
(deptno, grade), | (deptno, grade), | ||
(job, grade) ) | (deptno, job), | ||
(job, grade), | |||
(job), | |||
(grade), | |||
(deptno) | |||
) | |||
order by deptno, job, grade | order by deptno, job, grade | ||
; | ; | ||
--> | |||
== Hierarchy == | |||
* Using '''outer joins''' only | |||
* Recursively with '''CTE''' (''Common Table Expression'') | |||
* Built-in support - '''hierarchyid''' column type | |||
=== Outer joins example === | |||
<syntaxhighlight lang="sql"> | |||
-- Show all workers and their bosses, within 3 levels of hierarchy. | |||
SELECT W.ename AS Level0, B.ename AS Level1, B2.ename AS Level2, B3.ename AS Level3 | |||
FROM emp W LEFT JOIN emp B ON W.mgr = B.id | |||
LEFT JOIN emp B2 ON B.mgr = B2.id | |||
LEFT JOIN emp B3 ON B2.mgr = B3.id | |||
ORDER BY 4, 3, 2 | |||
; | |||
</syntaxhighlight> | |||
=== CTE Example === | |||
<syntaxhighlight lang="sql"> | |||
-- Steps | |||
---- 1. CTE, used in recursion | |||
---- 2. UNION ALL | |||
---- 3. INNER JOIN | |||
</syntaxhighlight> | |||
=== CTE Ex Skeleton === | |||
<syntaxhighlight lang="sql"> | |||
-- Rewrite above 'join' solution into 'recursive CTE' | |||
WITH ... | |||
AS (SELECT ... | |||
UNION ALL | |||
SELECT ... | |||
) | |||
SELECT * | |||
FROM ... | |||
; | |||
</syntaxhighlight> | |||
=== CTE Exercises === | |||
# Get the '''level for each node''' | |||
# Get the '''path for each node''' | |||
# Get the '''sorted hierarchy tree result''' | |||
#* parent followed by all of its children, then all the children of each one of those and so on | |||
#* use functions '''row_number()''' and '''power()''' | |||
<!-- Solution Ex 1 | |||
WITH hierarchicalList | |||
AS (SELECT PoshBoss.id, PoshBoss.ename, PoshBoss.mgr, 0 AS EmpLev | |||
FROM emp AS PoshBoss | |||
WHERE PoshBoss.mgr IS NULL | |||
UNION ALL | |||
SELECT PoorWorky.id, PoorWorky.ename, PoorWorky.mgr, Levels.EmpLev + 1 | |||
FROM emp AS PoorWorky INNER JOIN hierarchicalList AS Levels ON PoorWorky.mgr = Levels.id | |||
WHERE PoorWorky.mgr IS NOT NULL | |||
) | |||
SELECT * | |||
FROM hierarchicalList | |||
; | |||
--> | |||
<!-- Solution Ex2 | |||
with chL as ( | |||
select id, ename, cast(ename as varchar(200)) as hierPath | |||
from emp where id = 7839 | |||
union all | |||
select r.id, r.ename, cast(chL.hierPath + ' / ' + r.ename as varchar(200)) as hierPath | |||
from emp r inner join chL on chL.id = r.mgr | |||
) | |||
select * from chL; | |||
--> | |||
<!-- Solution Ex3 | |||
with chL as ( | |||
select id, ename, cast(ename as varchar(200)) as hierPath, 0 as lvl, | |||
row_number() over (partition by mgr order by ename) / power(10.0,1) as sortNo | |||
from emp where id = 7839 | |||
union all | |||
select r.id, r.ename, cast(chL.hierPath + ' / ' + r.ename as varchar(200)) as hierPath, chL.lvl+1 as lvl, | |||
chL.sortNo + row_number() over (partition by r.mgr order by r.ename) / power(10.0, chL.lvl+1) as sortNo | |||
from emp r inner join chL on chL.id = r.mgr | |||
) | |||
select * from chL | |||
order by sortNo; | |||
--> | |||
=== hierarchyid ''Example & Exercises'' === | |||
[[SQL_Exercises#hierarchyid_%28mssql%29|hierarchyid]] | |||
<!-- | |||
<syntaxhighlight lang="sql"> | |||
-- TODO | |||
</syntaxhighlight> | |||
=== hierarchyid Exercise === | |||
<syntaxhighlight lang="sql"> | |||
-- TODO | |||
</syntaxhighlight> | |||
--> | |||
== Analytic functions == | |||
* <small>https://learn.microsoft.com/en-us/sql/t-sql/functions/analytic-functions-transact-sql?view=sql-server-ver16</small> | |||
<syntaxhighlight lang="sql"> | |||
-- Example 1 | |||
---- Find the 2 highest paid employees in each department | |||
SELECT deptno, ename, sal | |||
FROM | |||
( | |||
SELECT | |||
deptno, ename, sal, | |||
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal desc) rn | |||
FROM emp | |||
) AS context | |||
WHERE rn <= 2 | |||
ORDER BY deptno, sal DESC; | |||
-- Exercise 1 | |||
---- Count cumulative distribution of salaries by manager | |||
------ only for people from departments 10 and 30 | |||
------ sort it by hierarchy and id | |||
-- Exercise 2 | |||
---- Extend above with also percent rank | |||
------ show department name | |||
------ sort it within window by hierarchy | |||
</syntaxhighlight> | |||
<!-- Solutions | |||
SELECT mgr, id, sal, | |||
CUME_DIST() OVER (PARTITION BY mgr ORDER BY sal) "Cum dist by Mgr" | |||
FROM emp | |||
WHERE deptno IN (10, 30) | |||
ORDER BY mgr, id; | |||
SELECT e.deptno, ename, mgr, dname, | |||
CUME_DIST () OVER (PARTITION BY e.deptno ORDER BY mgr) AS CumeDist, | |||
PERCENT_RANK() OVER (PARTITION BY e.deptno ORDER BY mgr ) AS PctRank | |||
FROM emp AS e | |||
INNER JOIN dept AS d | |||
ON d.deptno = e.deptno | |||
WHERE e.deptno IN (10, 30) | |||
ORDER BY e.deptno, mgr DESC; | |||
--> | |||
=== LAG, LEAD === | |||
<syntaxhighlight lang="sql"> | |||
------ LAG vs LEAD example - no need to use 'self-join' | |||
--- For each Clerk find the salary of the employee hired just before | |||
SELECT hiredate, ename, sal, | |||
LAG(sal, 1, 0) OVER (ORDER BY hiredate) AS prev_sal | |||
FROM emp | |||
WHERE job = 'CLERK' | |||
ORDER BY hiredate; | |||
---------------------- | |||
-- Exercise | |||
--- For each employee in Department 30 find the hire date of the employee hired just after | |||
</syntaxhighlight> | |||
<!-- Solution | |||
SELECT hiredate, ename, | |||
LEAD(hiredate, 1) OVER (ORDER BY hiredate) AS "NextHired" | |||
FROM emp | |||
WHERE deptno = 30 | |||
ORDER BY hiredate; | |||
--> | |||
=== FIRST, LAST === | |||
<syntaxhighlight lang="sql"> | |||
-- Return the employee with the fewest monies compared to other employees with the same job title | |||
SELECT job, | |||
ename, | |||
sal, | |||
dname, | |||
FIRST_VALUE(ename) OVER ( | |||
PARTITION BY job ORDER BY sal ASC ROWS UNBOUNDED PRECEDING | |||
) AS FewestMonies | |||
FROM emp AS e | |||
INNER JOIN dept AS d | |||
ON e.deptno = d.deptno | |||
ORDER BY job; | |||
------------------------- | |||
-- Exercise | |||
---- Return the hire date of the last employee in each department for the given salary | |||
------ show department name and monies grade | |||
</syntaxhighlight> | |||
<!-- Solution | |||
SELECT e.deptno, | |||
ename, | |||
sal, | |||
dname, | |||
grade, | |||
hiredate, | |||
LAST_VALUE(hiredate) OVER ( | |||
PARTITION BY e.deptno ORDER BY sal | |||
) AS LastValue | |||
FROM emp AS e | |||
INNER JOIN dept AS d | |||
ON e.deptno = d.deptno | |||
INNER JOIN salgrade AS s | |||
ON sal BETWEEN losal AND hisal | |||
WHERE e.deptno IN (10, 30); | |||
--> | --> | ||
Latest revision as of 15:14, 22 August 2024
SQL Advanced in MS SQL Training Materials
IMPORTANT NOTE for trainers only: Please DO NOT change these materials, especially the EXERCISES, without direct permission from LUKASZ SOKOLOWSKI.
Copyright Notice
Copyright © 2004-2023 by NobleProg Limited All rights reserved.
This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise.
Recap of Structured Query Language
- DDL
- DML
DDL
Data Definition Language
- A collection of imperative verbs
- Modify the schema of the database
- Adding, changing, or deleting definitions of tables or other objects
DDL Statements
Examples
- CREATE ...
- FUNCTION, DATABASE, PROCEDURE, TYPE, USER, VIEW, SCHEMA
- ALTER ...
- INDEX, TABLE, TRIGGER
- DROP ...
- RULE, STATISTICS, SYNONYM
- Other DDL statements
- ENABLE TRIGGER - DISABLE TRIGGER - TRUNCATE TABLE - UPDATE STATISTICS
- More here - learn.microsoft.com/en-us/sql/t-sql/statements/statements
DML
Data Manipulation Language
- Used to insert, query, delete and update data in a database
- Comprises the 'SQL-data change' statements
- Modify stored data but not the schema or database objects
DML Statements
- SELECT
- INSERT
- DELETE
- UPDATE
- MERGE
Exercises
- Escape in LIKE, more special characters
- CASE expression
- Grouping sets
- Hierarchical queries
- Analytic functions
- Insert
- Delete
- Update
- Stored procedures
- Transactions
- Cursors
- Triggers
- Procedural programming, handling errors
Escape in LIKE, more special characters
--- DB preps
USE mike
GO
CREATE TABLE [dbo].[dept2](
[DEPTNO] [numeric](2, 0) NOT NULL,
[DNAME] [char](14) NULL,
[LOC] [char](13) NULL,
)
INSERT INTO dept2(DEPTNO, DNAME, LOC)
VALUES (10, 'ACCOUNTING', 'NEW_YORK');
INSERT INTO dept2(DEPTNO, DNAME, LOC)
VALUES (20, 'RESEARCH', 'OLD_TOWN');
INSERT INTO dept2(DEPTNO, DNAME, LOC)
VALUES (30, 'SALES', 'PARIS');
INSERT INTO dept2(DEPTNO, DNAME, LOC)
VALUES (40, 'OPERATIONS', 'BERLIN');
--- Escape string in LIKE clause
SELECT
dname, loc
FROM
dept2
WHERE
loc LIKE '%\_YORK' ESCAPE '\'
;
More specials in LIKE
- [e-k] range
- [bs] set
- [^] negation (not) of range or set
- [_], [%] simpler escaping
- Examples
SELECT dname, loc FROM dept2
WHERE
loc LIKE '%[_]%'
-- dname LIKE '[a-o]%'
-- dname LIKE '[an]%'
-- dname LIKE '[^or]%'
;
- Exercises
- Find all employee names containing letters L or N or W
- Find all employee names containing letters L and N and W
- Search for people hired not in months: Jan and Dec
CASE expression
- Example
---- Case examples
-- Simple vs Searched
SELECT DISTINCT job, sal,
---- Simple - same condition
(CASE grade
WHEN 5 THEN 'Bossy'
WHEN 4 THEN 'CEO monies'
ELSE 'Peanuts' END) AS How_Much,
---- Searched - multiple conditions
(CASE
WHEN sal BETWEEN 500 AND 1200 THEN 'Rice'
WHEN ((sal BETWEEN 1250 AND 1800) AND comm IS NULL ) THEN 'Beans'
ELSE 'Coconuts' END) AS "Who's rich?"
FROM emp JOIN salgrade
ON sal BETWEEN losal AND hisal
ORDER BY 2;
---------------------------------
---- https://docs.oracle.com/cd/B19306_01/server.102/b14200/expressions004.htm
- Exercise - Calculate report per job, like below
- summarize salary bigger than 2000, otherwise put 0
- average of commissions lower than 1000, otherwise 0
- how many people
-- 5 rows ---------------------------------------------------------------------- Job Summarized Salary Average Commission Number of people ---------------------------------------------------------------------- ANALYST 6000 0 2 CLERK 0 0 4 SALESMAN 0 200 4 MANAGER 8275 0 3 PRESIDENT 5000 0 1 ----------------------------------------------------------------------
Grouping sets
------ EXAMPLE - GROUPING SETS
---- Exercises
-- 1. Compare it with simple grouping (undo the comment)
-- 2. Improve it - group also by 'grade' and count it
----
select deptno, job, sum(sal)
from emp
where deptno in (20, 30)
-- group by deptno, job
group by GROUPING SETS(
(deptno, job),
(deptno),
(job) )
order by deptno, job
;
Hierarchy
- Using outer joins only
- Recursively with CTE (Common Table Expression)
- Built-in support - hierarchyid column type
Outer joins example
-- Show all workers and their bosses, within 3 levels of hierarchy.
SELECT W.ename AS Level0, B.ename AS Level1, B2.ename AS Level2, B3.ename AS Level3
FROM emp W LEFT JOIN emp B ON W.mgr = B.id
LEFT JOIN emp B2 ON B.mgr = B2.id
LEFT JOIN emp B3 ON B2.mgr = B3.id
ORDER BY 4, 3, 2
;
CTE Example
-- Steps
---- 1. CTE, used in recursion
---- 2. UNION ALL
---- 3. INNER JOIN
CTE Ex Skeleton
-- Rewrite above 'join' solution into 'recursive CTE'
WITH ...
AS (SELECT ...
UNION ALL
SELECT ...
)
SELECT *
FROM ...
;
CTE Exercises
- Get the level for each node
- Get the path for each node
- Get the sorted hierarchy tree result
- parent followed by all of its children, then all the children of each one of those and so on
- use functions row_number() and power()
hierarchyid Example & Exercises
Analytic functions
-- Example 1
---- Find the 2 highest paid employees in each department
SELECT deptno, ename, sal
FROM
(
SELECT
deptno, ename, sal,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal desc) rn
FROM emp
) AS context
WHERE rn <= 2
ORDER BY deptno, sal DESC;
-- Exercise 1
---- Count cumulative distribution of salaries by manager
------ only for people from departments 10 and 30
------ sort it by hierarchy and id
-- Exercise 2
---- Extend above with also percent rank
------ show department name
------ sort it within window by hierarchy
LAG, LEAD
------ LAG vs LEAD example - no need to use 'self-join'
--- For each Clerk find the salary of the employee hired just before
SELECT hiredate, ename, sal,
LAG(sal, 1, 0) OVER (ORDER BY hiredate) AS prev_sal
FROM emp
WHERE job = 'CLERK'
ORDER BY hiredate;
----------------------
-- Exercise
--- For each employee in Department 30 find the hire date of the employee hired just after
FIRST, LAST
-- Return the employee with the fewest monies compared to other employees with the same job title
SELECT job,
ename,
sal,
dname,
FIRST_VALUE(ename) OVER (
PARTITION BY job ORDER BY sal ASC ROWS UNBOUNDED PRECEDING
) AS FewestMonies
FROM emp AS e
INNER JOIN dept AS d
ON e.deptno = d.deptno
ORDER BY job;
-------------------------
-- Exercise
---- Return the hire date of the last employee in each department for the given salary
------ show department name and monies grade
Example 1, 'WITH'
WITH functions_names as (
SELECT 'GetAllTheBookingForms' f union all
SELECT 'PrepareDelegatesDetails' f union all
SELECT 'HelperFunction' f
)
SELECT
f "Function name",
lower( f )
as "FN after"
FROM functions_names;
Exercise 1, 'INSERT' and 'WITH'
- Create a table (FinancialReport): Ename, Dname, Grade
- Insert into it all the related data - only from Sales and Accounting
- Do it via WITH
Exercise 2, 'DELETE' and 'OUTPUT'
- Remove grades 3 and 1 from FinancialReport
- Save the deleted rows in a variable (temporary table)
Exercise 3, 'UPDATE'
- Actualize grade 4: boost it up to 4k, make sure the rest of the data is consistent
- Compare the old and new values in temporary variable (table)
Example 4, 'Stored Procedures', with 'INPUT' and 'OUTPUT' accordingly
- https://docs.microsoft.com/en-us/sql/t-sql/statements/create-procedure-transact-sql?redirectedfrom=MSDN&view=sql-server-ver16#d-create-a-procedure-with-input-parameters
- https://docs.microsoft.com/en-us/sql/t-sql/statements/create-procedure-transact-sql?redirectedfrom=MSDN&view=sql-server-ver16#f-use-output-parameters
Exercise 4a, 'Stored Procedures' with 'INPUT'
- Prepare the procedure which will search for 'job' and 'sal'
Exercise 4b, 'Stored Procedures' with 'OUTPUT'
- Invent the procedure which will return name and all the possible monies the person can earn in next 5 years.
Example 5, 'Transactions'
Exercise 5, 'Transactions'
- Create simple named transaction which rises all the commissioned guys with 100 quid.
Example 6, 'Cursors'
Exercise 6, 'Fetch'
- Fetch people with names ending with N or R.
Example 7, 'Triggers'
Exercise 7, 'Trigger' and 'DDL'
- Run the above example and test it (=
Example 8, 'Procedural Programming'
Exercise 8, 'Procedural Programming'
- Delete person only if he/she has no subordinates (use procedure and transaction with the save point)