Download presentation
Presentation is loading. Please wait.
1
Multi-table queries Subqueries
DBMAN 4 Multi-table queries Subqueries SzaboZs
2
SELECT Displayed order of suffixes
INTO FROM WHERE GROUP BY HAVING UNION/MINUS INTERSECT ORDER BY SzaboZs
3
Multi-table queries Subqueries Examples
DBMAN 4 Multi-table queries Subqueries Examples SzaboZs
4
SET OPERATORS [query] [set operator] [query]
Important: two queries with same number of columns! Operators: UNION / UNION ALL, INTERSECT, MINUS / EXCEPT E.g.: SELECT min(sal) as ThreeValues FROM emp UNION SELECT avg(sal) FROM emp UNION SELECT max(sal) FROM emp; MySQL: MINUS = LEFT JOIN + WHERE … IS NULL SzaboZs
5
Table structure diagram
SzaboZs
6
Querying multiple tables
SELECT * FROM emp, dept; SELECT * FROM emp, emp; SELECT * FROM emp a, emp b; SELECT a.empno, a.ename, b.empno, b.ename FROM emp a, emp b; SELECT a.ename, a.deptno, b.deptno, b.dname FROM emp a, dept b; „Cross Join” Cartesian product EMP DEPT SzaboZs
7
"MANUAL JOIN" SELECT a.ename, a.deptno, b.deptno, b.dname FROM emp a, dept b WHERE a.deptno=b.deptno; Works – every record has a pair! SELECT a.empno, a.ename, a.mgr, b.empno, b.ename, b.mgr FROM emp a, emp b WHERE a.mgr=b.empno; Where is King??? no pair found! SzaboZs
8
JOIN Goes into the FROM part of a query
SELECT * FROM table1, table2 SELECT * FROM table1 JOIN_EXPRESSION table2 JOIN_CONDITION Joining tables = connecting the foreign keys to the primary keys Joining indexed fields is fast, joining non-indexed (non-key) fields is very slow good-to-avoid, cannot-always-avoid SzaboZs
9
NATURAL / INNER JOIN Same result as with "MANUAL JOIN" Only shows the records with valid pairs SELECT * FROM emp NATURAL INNER JOIN dept; -- Not in MySQL/TSQL! SELECT * FROM emp NATURAL JOIN dept; -- Not in TSQL SELECT * FROM emp INNER JOIN dept using (deptno); -- Not in TSQL SELECT * FROM emp INNER JOIN dept on (emp.deptno=dept.deptno); -- Works everywhere! SzaboZs
10
LEFT JOIN … ON … It must be used if we want to display the records WHERE there is no matching primary key record The nonexistent records' fields will be filled with NULL values use IFNULL/ISNULL/NVL if needed SELECT a.ename, a.deptno, b.deptno, b.dname FROM emp a LEFT JOIN dept b ON a.deptno=b.deptno; -- No difference here, as every worker has a department SELECT a.empno, a.ename, a.mgr, b.empno, b.ename, b.mgr FROM emp a LEFT JOIN emp b ON a.mgr=b.empno; -- KING is shown! SzaboZs
11
LEFT/RIGHT JOIN … ON … SELECT a.ename, a.deptno, b.deptno, b.dname FROM emp a RIGHT JOIN dept b ON a.deptno=b.deptno; OPERATIONS (40) is shown as well! Show everyone as a boss, even those who are no bosses list unpaired records from the other side! SELECT a.empno, a.ename, a.mgr, b.empno, b.ename, b.mgr FROM emp a RIGHT JOIN emp b ON a.mgr=b.empno; SELECT a.empno, a.ename, a.mgr, b.empno, b.ename, b.mgr FROM emp b LEFT JOIN emp a ON a.mgr=b.empno; The LEFT JOIN is more used SzaboZs
12
JOIN / ORACLE ONLY SELECT * FROM emp d, emp f WHERE d.mgr=f.empno (+);
SELECT * FROM emp d LEFT JOIN emp f ON (d.mgr=f.empno) SELECT * FROM emp d, emp f WHERE d.mgr(+)=f.empno; SELECT * FROM emp d RIGHT JOIN emp f ON (d.mgr=f.empno) SzaboZs
13
FULL JOIN LEFT JOIN + RIGHT JOIN
SELECT a.empno, a.ename, a.mgr, b.empno, b.ename, b.mgr FROM emp a FULL JOIN emp b ON a.mgr=b.empno; [The standard names this type as UNION JOIN; unavailable in MySQL…] Use the "MANUAL" JOIN and the LEFT JOIN SzaboZs
14
BAD JOIN??? SELECT ename, sal, dname FROM emp, dept WHERE emp.deptno=dept.deptno; SELECT ename, sal, dname FROM emp, dept WHERE emp.deptno=dept.deptno AND ename like '%E%'; SELECT ename, sal, dname FROM emp, dept WHERE emp.deptno=dept.deptno AND ename like '%E%' OR sal<3000; SELECT ename, sal, dname FROM emp, dept WHERE emp.deptno=dept.deptno AND (ename like '%E%' OR sal<3000); SzaboZs
15
JOINING TABLES SzaboZs
16
JOINING TABLES SzaboZs
17
JOINING TABLES SzaboZs
18
JOINING TABLES SELECT * FROM emp worker, emp boss, dept work_dept, dept boss_dept WHERE worker.mgr=boss.empno AND worker.deptno=work_dept.deptno AND boss.deptno=boss_dept.deptno; Good, if we don't want to see the unpaired records SzaboZs
19
JOINING TABLES SELECT * FROM emp worker LEFT JOIN emp boss ON (worker.mgr=boss.empno), dept work_dept, dept boss_dept WHERE worker.deptno=work_dept.deptno AND boss.deptno=boss_dept.deptno; NOT CHANGES ANYTHING SzaboZs
20
JOINING TABLES SELECT * FROM emp worker LEFT JOIN emp boss ON (worker.mgr=boss.empno) LEFT JOIN dept boss_dept ON (boss.deptno=boss_dept.deptno) LEFT JOIN dept work_dept ON (worker.deptno=work_dept.deptno); PERFECT SzaboZs
21
JOINING TABLES After the join is made in the FROM/WHERE, the query can be built up just like as if it was a single-table query. Every suffix can be used, the result-table can be used the same way as with a single-table query PRACTICE and STRUCTURED QUERIES are required!!! SzaboZs
22
EXAMPLE Display every boss' name and the average salary of those sub-workers whose salary is bigger than 1000 USD. Only display those records where this average is smaller than 5000 USD. SzaboZs
23
EXAMPLE SELECT avg(a.sal) as AVERAGE, b.ename as BOSS
FROM emp a, emp b WHERE (a.mgr=b.empno) AND (a.sal>1000) GROUP BY b.ename HAVING avg(a.sal)<5000 ORDER BY AVERAGE desc; SzaboZs
24
EXAMPLE SELECT avg(a.sal) as AVERAGE, b.ename as BOSS FROM emp a
INNER JOIN emp b ON a.mgr=b.empno WHERE a.sal>1000 GROUP BY b.ename HAVING avg(a.sal)<5000 ORDER BY AVERAGE desc; SzaboZs
25
Multi-table queries Subqueries
DBMAN 4 Multi-table queries Subqueries SzaboZs
26
SUB-QUERIES Basic principle: in some parts of the main query (field list, WHERE suffix, FROM suffix) there is another query instead of a simple field name/expression/constant/ table sub-query MySQL only supports it with the newer (>4.1) versions (with some angry limitations…) SzaboZs
27
Sub-queries in the field list
You can put a constant in the field list you can put any sub-query there that returns with exactly one value SELECT sal, (SELECT max(sal) FROM emp) as maxSal, (SELECT max(sal) FROM emp)-sal as deltaSal FROM emp ORDER BY deltaSal desc; SzaboZs
28
Sub-queries in the FROM (inline view)
You can put any table in the FROM every query returns a table almost any sub-query can be used in the FROM, that we can use as a table in that query The sub-query must have an alias and must be written between parentheses SELECT * FROM (SELECT a.empno, a.ename, a.mgr, b.empno, b.ename FROM emp a, emp b WHERE a.mgr=b.empno) sub ORDER BY ename asc; Field names must be unique – use an alias!!! SzaboZs
29
Sub-queries in the FROM
SELECT bosses.work_name as Worker, bosses.boss_name as Boss FROM ( SELECT a.empno as work_id, a.ename as work_name, a.mgr as work_bossid, b.empno as boss_id, b.ename as boss_name FROM emp a, emp b WHERE a.mgr=b.empno) bosses ORDER BY Worker asc; SzaboZs
30
Sub-queries in the FROM
SELECT emp.deptno, min, ename FROM ( Select deptno, min(sal) as min From emp Group by deptno ) minimums, emp WHERE emp.sal=minimums.min and emp.deptno=minimums.deptno; SzaboZs
31
Sub-query in the WHERE Use constant values in the WHERE use any sub-query that returns with exactly one value SELECT ename, sal FROM emp WHERE sal>(SELECT avg(sal) FROM emp); SELECT ename, sal FROM emp WHERE sal=(SELECT min(sal) FROM emp); SzaboZs
32
Sub-query in the WHERE ALWAYS VERY SLOW SUBQUERY IN THE FROM IS BETTER SELECT ename, sal FROM emp WHERE sal>(SELECT avg(sal) FROM emp); SELECT ename, sal FROM emp, (SELECT avg(sal) as avgSal FROM emp) sub WHERE sal>sub.avgsal; (No JOIN caresian product, but the subquery only has one row it simply adds the one avgSal field to emp) SzaboZs
33
Sub-query in the WHERE Use lists in the WHERE use any sub-query that returns with exactly one column Operators: [NOT] IN / EXISTS, ANY, ALL Usually used with a subset: SELECT sal FROM emp WHERE upper(job)='SALESMAN'; SELECT sal FROM emp WHERE deptno = 10; SzaboZs
34
Sub-query in the WHERE SELECT ename, sal FROM emp WHERE sal IN (SELECT sal FROM emp WHERE deptno = 10); SELECT ename, sal FROM emp WHERE sal NOT IN (SELECT sal FROM emp WHERE deptno = 10); Correlated sub-query STILL SLOW! Subquery into the FROM! IN INNER JOIN NOT IN LEFT JOIN + WHERE xxx IS NULL Optimization is not important this semester SzaboZs
35
Sub-query in the WHERE SELECT ename, sal FROM emp WHERE sal> ANY (SELECT sal FROM emp WHERE deptno = 10); SELECT ename, sal FROM emp WHERE sal>(SELECT min(sal) FROM emp WHERE deptno = 10); Same results Oracle does an internal sort with the ANY!!! STILL SLOW! Subquery into the FROM! SzaboZs
36
Sub-query in the WHERE SELECT ename, sal FROM emp WHERE sal> ALL (SELECT sal FROM emp WHERE deptno = 30); SELECT ename, sal FROM emp WHERE sal>(SELECT max(sal) FROM emp WHERE deptno = 30); Same results, No automatic sort Always use the ORDER BY, if required STILL SLOW! Subquery into the FROM! Subquery should always go to the FROM … But how to avoid loooooooooooooooong queries? SzaboZs
37
Fetch hierarchy in one query
Oracle> SELECT level, empno, ename, mgr FROM emp START WITH empno=7839 CONNECT BY mgr=prior empno ORDER BY level desc; Standard, TSQL> no such way… TODO: recursive CTE … CTE = SUBSTITUTE a subquery with a name, usable only in the main query where the CTE is defined Similar object: views = STORE a subquery with a name, which is later usable in any main/subquery SzaboZs
38
CTE/VIEW CTE = Common Table Expression WITH xxx (columns) AS (SELECT …) SELECT * FROM xxx INNER JOIN otherTable … VIEW: GO CREATE VIEW xxx (columns) AS (SELECT …); GO SELECT * FROM xxx INNER JOIN otherTable … CREATE VIEW must be the only statement in the batch The column list is optional in both cases SzaboZs
39
CTE Example (AdventureWorks)
Task: which are the orders with the biggest ratio compared to the monthlyTotal? Pre-solution: monthly totals SELECT SUM(TotalDue) as monthlyTotal, datepart(month, OrderDate) as month FROM Sales.SalesOrderHeader GROUP BY datepart(month, OrderDate) SzaboZs
40
Ratios with CTE WITH statsMonthly AS (SELECT SUM(TotalDue) as monthlyTotal, datepart(month, OrderDate) as month FROM Sales.SalesOrderHeader GROUP BY datepart(month, OrderDate)) SELECT sh.SalesOrderID, sh.OrderDate, sh.TotalDue, sm.monthlyTotal, sh.TotalDue/sm.monthlyTotal as ratio FROM Sales.SalesOrderHeader sh INNER JOIN statsMonthly sm ON (datepart(month,sh.OrderDate)=sm.month) ORDER BY ratio desc; SzaboZs
41
Ratios with VIEW IF object_id('statsMonthly', 'V') is not null DROP VIEW statsMonthly; GO CREATE VIEW statsMonthly AS (SELECT SUM(TotalDue) as monthlyTotal, datepart(month, OrderDate) as month FROM Sales.SalesOrderHeader GROUP BY datepart(month, OrderDate)); SzaboZs
42
Ratios with VIEW SELECT sh.SalesOrderID, sh.OrderDate, sh.TotalDue, sm.monthlyTotal, sh.TotalDue/sm.monthlyTotal as ratio FROM Sales.SalesOrderHeader sh INNER JOIN statsMonthly sm ON (datepart(month, sh.OrderDate)=sm.month) ORDER BY ratio desc; CTE or View? Used once vs used many times Recursive CTEs are allowed – Recursive views are not always allowed (Postgresql, Teradata) SzaboZs
43
Recursive CTE – Fetch whole hierarchy
WITH recQ AS (SELECT empno, ename, mgr, 0 as wl FROM emp WHERE ename = 'KING' UNION ALL SELECT nplus1.empno, nplus1.ename, nplus1.mgr, recQ.wl+1 as wl FROM emp as nplus1, recQ WHERE recQ.empno = nplus1.mgr) SELECT ename, empno, mgr, wl FROM recQ SzaboZs
44
SzaboZs
45
SzaboZs
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.