Presentation is loading. Please wait.

Presentation is loading. Please wait.

Multi-table queries Subqueries

Similar presentations


Presentation on theme: "Multi-table queries Subqueries"— Presentation transcript:

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


Download ppt "Multi-table queries Subqueries"

Similar presentations


Ads by Google