Upload
kristian-leonard
View
222
Download
1
Embed Size (px)
Citation preview
V 1.0 OE NIK 2013 1
PHP+SQL10
(SQL 3)
Group By, HavingMulti-table queriesSubqueriesExamples
V 1.0
SELECTDisplayed order of suffixes
1. INTO2. FROM3. WHERE4. GROUP BY5. HAVING6. UNION/MINUS7. INTERSECT8. ORDER BY
2OE NIK 2013
V 1.0 OE NIK 2013 3
PHP+SQL10
(SQL 3)
Group By, HavingMulti-table queriesSubqueriesExamples
V 1.0
Grouping/Aggregate functions • SUM - Sum• AVG - Average• MIN - Minimum• MAX - Maximum• COUNT - Number of non null values (records)• GROUP_CONCAT - Concatenated list of elements• STDDEV - Standard deviation• VARIANCE - Variance
4OE NIK 2013
V 1.0
Non-grouping usage• select avg(sal) as Average from emp;• select min(sal) from emp;• select min(sal) from emp where sal>2000;• select avg(distinct sal) as Average from emp;• select count(sal) from emp;• select count(comm) from emp where sal>2000;• select comm from emp where sal>2000;• select count(*) from emp where sal>2000;• select avg(comm) from emp; NULL values are not
included!
5OE NIK 2013
V 1.0
Grouping• select distinct deptno from emp;• select avg(sal) from emp where deptno=10;• select avg(sal) from emp where deptno=20;• select avg(sal) from emp where deptno=30; select deptno, avg(sal) from emp group by deptno;
6OE NIK 2013
V 1.0
Grouping
IN THE SELECTION LIST (FIELD LIST) ONLY THE GROUPED FIELD(s) AND THE
GROUPING FUNCTION(s) ARE ALLOWED!
(YES, IN MYSQL AS WELL!!!)(ONLY_FULL_GROUP_BY)
• select deptno, avg(sal) as Average, min(sal) as Minimum, count(*) as Num from emp group by deptno;
7OE NIK 2013
V 1.0
Grouping and suffixes
• select mgr, avg(sal) from emp group by mgr;• select ifnull(mgr, "none") as boss, lpad(avg(sal), 15, '#')
as "Averagesal" from emp group by mgr;• HAVING vs. WHERE• select mgr, avg(sal) from emp where ename like '%E%'
group by mgr;• select mgr, avg(sal) from emp where ename like '%E%'
group by mgr having avg(sal)>1300;• select mgr, avg(sal) as average from emp where ename
like '%E%' group by mgr having avg(sal)>1300 order by average desc;
8OE NIK 2013
V 1.0
More complex grouping queries• select min(max(sal)), max(max(sal)),
round(avg(max(sal))) from emp group by deptno; -- In Oracle this works, in MySQL „Invalid use of group function”
• select min(sal+ nvl(comm,0)), mod(empno,3) from emp group by mod(empno,3) having min(sal+nvl(comm,0)) > 800;
9OE NIK 2013
V 1.0
• select distinct job, substr(job, 2, 1) from emp;• select avg(sal) as average, substr(job, 2, 1) from emp
group by substr(job, 2, 1);
• select ename, sal, round(sal/1000) from emp;• select round(sal/1000) as SalCat, count(sal) as Num
from emp group by round(sal/1000);
More complex grouping queries
10OE NIK 2013
V 1.0
• select ename, round(datediff(curdate(), hiredate)/365.25) as diff from emp;
• select count(*), round(datediff(curdate(), hiredate)/365.25) as diff from emp group by round(datediff(curdate(), hiredate)/365.25);
More complex grouping queries
11OE NIK 2013
V 1.0
• select distinct depno, job from emp;• select deptno, job, avg(sal), min(sal), max(sal) from
emp group by deptno, job order by deptno, job;
Oracle-specific „extras” (not required):– GROUP BY GROUPING SETS– GROUP BY CUBE– GROUP BY ROLLUP
More complex grouping queries
12OE NIK 2013
V 1.0 OE NIK 2013 13
PHP+SQL10
(SQL 3)
Group By, HavingMulti-table queriesSubqueriesExamples
V 1.0
SET OPERATORS• [query] [set operator] [query]• Important: two queries with same number of columns!• Operators: UNION, INTERSECT, MINUS / EXCEPT• E.g.: select min(sal) as MIN_AVG_MAX from emp UNION
select avg(sal) from emp UNION select max(sal) from emp;
• MySQL S***CKS: http://www.bitbybit.dk/carsten/blog/?p=71
14OE NIK 2013
V 1.0
Table structure diagram
15OE NIK 2013
V 1.0
Preparations• We already have a department without a worker
• create table emp1 as select * from emp;• create table dept1 as select * from dept;• update emp1 set deptno=50 where ename='WARD'; The new tables will be inconsistent, but we need this to
test everything• update emp1 set deptno=NULL where ename='WARD'; Now we have a department without worker (40) and a
worker without department (WARD)
16OE NIK 2013
V 1.0
Querying multiple tables• select * from emp1, dept1;• select * from emp1, emp1;• select * from emp1 a, emp1 b;• select a.empno, a.ename, b.empno, b.ename from emp1
a, emp1 b;• select a.ename, a.deptno, b.deptno, b.dname from
emp1 a,dept1 b;• „Cross Join” Cartesian product EMP1 DEPT1
17OE NIK 2013
V 1.0
"MANUAL JOIN"• select a.ename, a.deptno, b.deptno, b.dname from
emp1 a, dept1 b where a.deptno=b.deptno;• Where is Ward???• select a.empno, a.ename, a.mgr, b.empno, b.ename,
b.mgr from emp1 a, emp1 b where a.mgr=b.empno;• Where is King???
18OE NIK 2013
V 1.0
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
19OE NIK 2013
V 1.0
NATURAL / INNER JOIN• Same result as with "MANUAL JOIN" By default, it
only works with the same field names! (…)• select * from emp1 natural inner join dept1; -- Not in
MySQL!• select * from emp1 natural join dept1;• select * from emp1 inner join dept1 using (deptno);• select * from emp1 inner join dept1 on
(emp1.deptno=dept1.deptno);
20OE NIK 2013
V 1.0
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 if needed
• select a.ename, a.deptno, b.deptno, b.dname from emp1 a LEFT JOIN dept1 b ON a.deptno=b.deptno;
• select a.empno, a.ename, a.mgr, b.empno, b.ename, b.mgr from emp1 a LEFT JOIN emp1 b ON a.mgr=b.empno;
21OE NIK 2013
V 1.0
LEFT/RIGHT JOIN … ON …
• select a.ename, a.deptno, b.deptno, b.dname from emp1 a RIGHT JOIN dept1 b ON a.deptno=b.deptno;
• select a.ename, a.deptno, b.deptno, b.dname from dept1 b LEFT JOIN emp1 a ON a.deptno=b.deptno;
The LEFT JOIN is more used
22OE NIK 2013
V 1.0
JOIN / ORACLE
• SELECT * FROM emp1 d, emp1 fWHERE d.mgr=f.empno (+);
SELECT * FROMemp1 d LEFT JOIN emp1 f ON (d.mgr=f.empno)
• SELECT * FROM emp1 d, emp1 fWHERE d.mgr(+)=f.empno;
SELECT * FROMemp1 d RIGHT JOIN emp1 f ON (d.mgr=f.empno)
• SELECT level, empno, ename, mgr FROM emp START WITH empno=7839 CONNECT BY mgr=prior empno ORDER BY level desc;
23OE NIK 2013
V 1.0
FULL JOIN
• LEFT JOIN + RIGHT JOIN• select a.empno, a.ename, a.deptno, b. deptno,
b.dname from emp1 a FULL JOIN dept1 b ON (emp1.deptno=dept1.deptno);
• [The standard names this type as UNION JOIN; unavailable in MySQL…]
Use the "MANUAL" JOIN and the LEFT JOIN
24OE NIK 2013
V 1.0
JOIN MISTAKE???• 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);
25OE NIK 2013
V 1.0
JOINING TABLES
26OE NIK 2013
V 1.0
JOINING TABLES
27OE NIK 2013
V 1.0
JOINING TABLES
28OE NIK 2013
V 1.0
JOINING TABLES
• SELECT * FROMemp1 worker, emp1 boss,dept1 work_dept, dept1 boss_dept
WHEREworker.mgr=boss.empno ANDworker.deptno=work_dept.deptno ANDboss.deptno=boss_dept.deptno;
• Good, if we don't want to see the unpaired records
29OE NIK 2013
V 1.0
JOINING TABLES
• SELECT * FROMemp1 worker LEFT JOIN emp1 boss
ON (worker.mgr=boss.empno),dept1 work_dept, dept1 boss_dept
WHEREworker.deptno=work_dept.deptno ANDboss.deptno=boss_dept.deptno;
• NOT CHANGES ANYTHING
30OE NIK 2013
V 1.0
JOINING TABLES
• SELECT * FROMemp1 worker
LEFT JOIN emp1 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
31OE NIK 2013
V 1.0
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!!!
32OE NIK 2013
V 1.0
EXAMPLE
Display every boss' name and the average salary of those sub-workers who earn more than 1000 USD. Only display those records where this average is smaller than 5000 USD.
33OE NIK 2013
V 1.0
EXAMPLE
SELECT avg(a.sal) as AVERAGE, b.ename as BOSSFROM emp a, emp bWHERE (a.mgr=b.empno) AND (a.sal>1000)GROUP BY b.enameHAVING avg(a.sal)<5000ORDER BY AVERAGE desc;
34OE NIK 2013
V 1.0
EXAMPLE
SELECT avg(a.sal) as AVERAGE, b.ename as BOSSFROM emp a
LEFT JOIN emp b ON a.mgr=b.empnoWHERE a.sal>1000GROUP BY b.enameHAVING avg(a.sal)<5000ORDER BY AVERAGE desc;
35OE NIK 2013
V 1.0 OE NIK 2013 36
PHP+SQL10
(SQL 3)
Group By, HavingMulti-table queriesSubqueriesExamples
V 1.0
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…)
37OE NIK 2013
V 1.0
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 [more than one row / too many values / operand should contain 1 column(s)]
• SELECT sal,(select max(sal) from emp) as MAX,(select max(sal) from emp)-sal as DELTA FROM empORDER BY DELTA desc;
38OE NIK 2013
V 1.0
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 worker.salary from (select sal as salary from emp) worker order by salary desc;
• select * from (select a.empno, a.ename, a.mgr, b.empno, b.ename from emp a, emp b where a.mgr=b.empno) order by ename asc; -- Field names must be unique – use an alias!!!
39OE NIK 2013
V 1.0
Sub-queries in the FROMSELECT bosses.work_name as Worker,
bosses.boss_name as BossFROM ( 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) bossesORDER BY Worker asc;
40OE NIK 2013
V 1.0
Sub-queries in the FROMSELECT emp.deptno, min, enameFROM ( Select deptno, min(sal) as min From emp Group by deptno) minimums, empWHERE emp.sal=minimums.min and
emp.deptno=minimums.deptno;
41OE NIK 2013
V 1.0
Sub-query in the WHERE• Use constant values in the WHERE use any sub-query
that returns with exactly one value [more than one row / too many values / operand should contain 1 column(s)]
• 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 where sal=(select min(sal) from emp);
42OE NIK 2013
V 1.0
Sub-query in the WHERE
• Use lists in the WHERE use any sub-query that returns with exactly one column
• Operators: [NOT] IN, ANY, ALL• Példa:
select sal, mod(round(sal/1000), 2) from emp;
select sal from emp where mod(round(sal/1000), 2)=0;
select sal from emp where deptno = 10;
43OE NIK 2013
V 1.0
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 We’ll talk about optimization later Optimization is not important this semester
44OE NIK 2013
V 1.0
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!!!
45OE NIK 2013
V 1.0
Sub-query in the WHERE
• select ename, sal from emp where sal> ALL (select sal from emp where deptno = 10);
• 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
46OE NIK 2013
V 1.0 OE NIK 2013 47
PHP+SQL10
(SQL 3)
Group By, HavingMulti-table queriesSubqueriesExamples
V 1.0
Zero• List the name, job and income for the workers who work
in Dallas or Chicago.
• Looks easy… Let’s use operator IN
48OE NIK 2013
V 1.0
Solution using the INSELECT
ename, job, sal+nvl(comm, 0)FROM emp, deptWHERE
emp.deptno=dept.deptno ANDupper(dept.loc) IN ('DALLAS', 'CHICAGO');
SELECT ename, job, sal+nvl(comm, 0)
FROM empWHERE deptno IN (
SELECT deptno FROM deptWHERE upper(loc) IN ('DALLAS', 'CHICAGO')
);49OE NIK 2013
V 1.0
BAD Solution using manual joinSELECT
ename, job, sal+nvl(comm, 0)FROM
emp, deptWHERE
emp.deptno=dept.deptno ANDupper(dept.loc)='DALLAS' ORupper(dept.loc)='CHICAGO';
50OE NIK 2013
V 1.0
Solution using manual joinSELECT
ename, job, sal+nvl(comm, 0)FROM
emp, deptWHERE
emp.deptno=dept.deptno AND(upper(dept.loc)='DALLAS' ORupper(dept.loc)='CHICAGO');
51OE NIK 2013
V 1.0
• List the name of the workers, their salary, the name of their boss, the boss' departments' location and the sum salary of that place.
First
52OE NIK 2013
V 1.0
• Sum salary of a location join EMP and DEPT, use sum()
• Worker name and income EMP D• Boss name and income join EMP D and EMP F, use
EMP F• Place of the boss' department join EMP F and DEPT
CHOOSING TABLES AND FIELDS
53OE NIK 2013
V 1.0
SALARIES IN A DEPARTMENT• A simple multi-table GROUP BY• EMP_1 <deptno, deptno> DEPT_1, and then sum(sal)
grouped by the LOC field
54OE NIK 2013
V 1.0
SALARIES
SELECT sum(emp.sal) as dept_sal,dept.loc as dept_loc
FROM emp, deptWHERE emp.deptno=dept.deptnoGROUP BY dept.loc;
55OE NIK 2013
V 1.0
• Workers' name and salary EMP_2• Boss' name and salary join EMP_2 and EMP_3, use
fields in EMP_3• Boss' department's name Join EMP_3 and DEPT_2
EMP_2 <empno, mgr> EMP_3 EMP_3 <deptno, deptno> DEPT_2
WORKERS-BOSSES-BOSS' DATA
56OE NIK 2013
V 1.0
WORKERS-BOSSES-BOSS' DATA
57OE NIK 2013
V 1.0
SELECT work.ename as work_name,work.sal as work_sal,boss.ename as boss_name,boss.sal as boss_sal,dept.loc as boss_loc
FROM emp work, emp boss, deptWHERE work.mgr=boss.empno and
boss.deptno=dept.deptno;
WORKERS-BOSSES-BOSS' DATA
58OE NIK 2013
V 1.0
RESULT
• WORKERS-BOSSES-BOSS' DATA data1 • SUM-SALARIES data2• data1 <boss_loc, dept_loc> data2
59OE NIK 2013
V 1.0
SELECT * from(SELECT work.ename as work_name,
work.sal as work_sal,boss.ename as boss_name,boss.sal as boss_sal,dept.loc as boss_loc
FROM emp work, emp boss, deptWHERE work.mgr=boss.empno and
boss.deptno=dept.deptno) data1,(SELECT sum(emp.sal) as dept_sal,
dept.loc as dept_locFROM emp, deptWHERE emp.deptno=dept.deptnoGROUP BY dept.loc) data2
WHERE data1.boss_loc=data2.dept_locORDER BY boss_name, work_name;
60OE NIK 2013
V 1.0
Second
List the number of employees for each boss, along with their departments, average income, and the difference between that average and the boss' income.
Now do we need the department of the boss (A), or the workers (B)???
61OE NIK 2013
V 1.0
• Number of employees, their average income GROUP BY EMP.MGR
• Department Joining EMP and DEPT
CHOOSING FIELDS AND TABLES
62OE NIK 2013
V 1.0
GROUP BY EMP.MGR• We can create a table that looks like boss_id –
avg.income – num.of.workers, that can be joined to the other tables
• How to join: that depends if we interpret the exercise as "A" or "B"
63OE NIK 2013
V 1.0
SELECT avg(sal+nvl(comm, 0)) as avg_work_sal,count(*) as work_num,mgr as boss_id
FROM empGROUP BY mgr
Inline view: Data After this: joining tables
Worker's number and average income
64OE NIK 2013
V 1.0
Joining tables (A)
65OE NIK 2013
V 1.0
Joining tables (B)
66OE NIK 2013
V 1.0
Joining tables (A)
67OE NIK 2013
V 1.0
SELECT emp.ename as boss_name,emp.sal+nvl(emp.comm, 0) as boss_sal,data.avg_work_sal as boss_worker_sal,data.work_num as boss_worker_num,dept.loc as boss_loc,emp.sal+nvl(emp.comm, 0) - data.avg_work_sal as sal_delta
FROM( SELECT avg(sal+nvl(comm, 0)) as avg_work_sal,
count(*) as work_num,mgr as boss_id
FROM empGROUP BY mgr) data, emp, deptWHERE data.boss_id=emp.empno and emp.deptno=dept.deptno; 68OE NIK 2013
V 1.0
Joining tables (B)
69OE NIK 2013
V 1.0
SELECT d.ename as work_name,f.ename as boss_name,f.sal+nvl(f.comm, 0) as boss_sal,data.avg_work_sal as boss_worker_sal,data.work_num as boss_worker_num,dept.loc as worker_loc,f.sal+nvl(f.comm, 0) -data.avg_work_sal as
sal_delta FROM(SELECT avg(sal+nvl(comm, 0)) as avg_work_sal,
count(*) as work_num,mgr as boss_id
FROM empGROUP BY mgr) data, emp d, emp f, deptWHERE data.boss_id=f.empno and
f.empno=d.mgr and d.deptno=dept.deptno ;
70OE NIK 2013
V 1.0
ThirdList the jobs according to the departments, and the
number of workers, the minimum and maximum salaries according to that job. Order the list by the department (ascending) and job (descending).
71OE NIK 2013
V 1.0
JOB-DATA DATA1SELECT count(*) as Work_Num,
min(sal+nvl(comm, 0)) as Minimum,max(sal+nvl(comm, 0)) as Maximum,avg(sal+nvl(comm, 0)) as Average,job
FROM empGROUP BY job;
72OE NIK 2013
V 1.0
DEPARTMENTS AND JOBS DATA2SELECT distinct loc, jobFROM emp, deptWHERE emp.deptno=dept.deptnoORDER BY loc;
73OE NIK 2013
V 1.0
RESULT (A)SELECT * FROM(SELECT distinct dept.deptno, loc, job
FROM emp, deptWHERE emp.deptno=dept.deptnoORDER BY loc) data2,
(SELECT count(*) as Work_Num,min(sal+nvl(comm, 0)) as Minimum,max(sal+nvl(comm, 0)) as Maximum,avg(sal+nvl(comm, 0)) as Average,jobFROM empGROUP BY job) data1
WHERE data1.job=data2.jobORDER BY data2.deptno asc, data1.job desc;
74OE NIK 2013
V 1.0
RESULT (B)
SELECT count(*) as Work_Num,min(sal+nvl(comm, 0)) as Minimum,max(sal+nvl(comm, 0)) as Maximum,avg(sal+nvl(comm, 0)) as Average,job, deptnoFROM empGROUP BY job, deptnoORDER BY deptno asc, job desc;
75OE NIK 2013
V 1.0
Fourth• Display every worker’s name, their department’s name,
their boss’ name. The list should include the income parameter for both the boss and the worker.
• Income parameter: (income) – (the average income of those who entered the company the same year)
76OE NIK 2013
V 1.0 OE NIK 2013 77
78OE NIK 2013