Professional Documents
Culture Documents
Un Pivot
Un Pivot
University of Wolverhampton, UK
Introduction
Working with Oracle since 1986
Oracle DBA - OCP Oracle7, 8, 9, 10 Oracle DBA of the Year 2002
Member of IOUC
Day job University of Wolverhampton, UK
Carl Dudley University of Wolverhampton 2
Scoping in SQL
SELECT ename ,job ,deptno ,sal FROM emp WHERE deptno = 10 AND job IN (SELECT job FROM emp WHERE deptno = (SELECT deptno FROM dept WHERE dname = 'SALES')) ENAME ---------CLARK MILLER JOB DEPTNO SAL --------- --------- --------MANAGER 10 2450 CLERK 10 1300 dept table DEPTNO DNAME SAL ------ --------- --------10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON
SELECT ename FROM emp WHERE job IN (SELECT dept.job FROM dept) * ERROR at line 1: ORA-00904: "DEPT.JOB": invalid identifier
Aggregate Functions
SELECT sal FROM emp WHERE deptno = 99;
no rows selected. expected empty set If the aggregate function AVG is applied to an empty set, it should return an undefined value SELECT AVG(sal) FROM emp WHERE deptno = 99; AVG(SAL) -------<---- NULL value Unfortunate if testing for NO_DATA_FOUND, or if this was a subquery GROUP BY seems to overcome the problem SELECT AVG(sal) FROM emp WHERE deptno = 99 GROUP BY (); no rows selected. SELECT AVG(sal),1 FROM emp WHERE deptno = 99 GROUP BY (1); no rows selected.
SELECT SUM(sal) FROM emp WHERE deptno = 99; SUM(SAL) -------NULL SELECT SUM(sal) FROM emp WHERE deptno = 99 GROUP BY deptno; no rows selected. SELECT COUNT(*) FROM emp WHERE deptno = 99; COUNT(SAL) ---------0
COUNT(SAL) ---------0
SELECT COUNT(sal) FROM emp WHERE deptno = 99 GROUP BY deptno; no rows selected. SELECT sal FROM emp WHERE deptno = 99; no rows selected.
10
11
SAL COMM DEPTNO ---- ----- -----1500 0 30 1250 500 30 1250 1400 30 1600 300 30 1300 10 800 20 1100 20 950 30
Attempt to find them using NOT IN SELECT * FROM emp WHERE empno NOT IN (SELECT mgr FROM emp); no rows selected.
This is correct behaviour
Carl Dudley University of Wolverhampton
12
13
SELECT * FROM emp x WHERE NOT EXISTS (SELECT 1 FROM emp y WHERE x.empno = y.mgr);
EMPNO ----7844 7521 7654 7499 7934 7369 7876 7900 ENAME -----TURNER WARD MARTIN ALLEN MILLER SMITH ADAMS JAMES JOB --------SALESMAN SALESMAN SALESMAN SALESMAN CLERK CLERK CLERK CLERK MGR ---7698 7698 7698 7698 7782 7902 7788 7698 HIREDATE --------08-SEP-81 22-FEB-81 28-SEP-81 20-FEB-81 23-JAN-82 17-DEC-80 12-JAN-83 03-DEC-81 SAL COMM DEPTNO ---- ----- -----1500 0 30 1250 500 30 1250 1400 30 1600 300 30 1300 10 800 20 1100 20 950 30
14
15
NOT IN plan
SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT HASH JOIN ANTI NA TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP
9i
10g
11g
9i
10g
11g
9i
10g
11g
9i
10g
11g
SELECT STATEMENT HASH JOIN ANTI SNA TABLE ACCESS FULL DEPT INDEX FULL SCAN EMP$DEPTNO
SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT INDEX FAST FULL SCAN EMP$DEPTNO
If the column on the right hand side of the condition (emp.deptno) has no NOT NULL constraint, then NA is used If it is declared NOT NULL, SNA is used, along with an available index
Carl Dudley University of Wolverhampton 19
20
ANYthing Goes
SELECT ename ,sal ,deptno FROM emp WHERE sal > ANY(SELECT e1.sal FROM emp e1 WHERE e1.deptno = 30) SELECT ename ,sal ,deptno FROM emp e1 WHERE sal > (SELECT MIN(e1.sal) FROM emp e1 WHERE e1.deptno = 30)
ENAME SAL DEPTNO ------- ----- -----ALLEN 1600 30 WARD 1250 30 JONES 2975 20 MARTIN 1250 30 BLAKE 2850 30 CLARK 2450 10 SCOTT 3000 20 KING 5000 10 TURNER 1500 30 ADAMS 1100 20 FORD 3000 20 MILLER 1300 10
Carl Dudley University of Wolverhampton 21
ANY vs MIN
The empany table has only one row EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ----- ---------- --------- ---- --------- ---- ---- -----7369 SMITH CLERK 7902 17-DEC-80 800 20 Find all employees who do not earn more than anyone outside of their department SELECT e.empno FROM empany e WHERE NOT(e.sal > (SELECT MIN(e2.sal) FROM empany e2 WHERE e2.deptno <> e.deptno)); no rows selected
SELECT e.empno FROM empany e WHERE NOT(e.sal > ANY(SELECT (e2.sal) FROM empany e2 WHERE e2.deptno <> e.deptno)); EMPNO ----7369
Carl Dudley University of Wolverhampton 23
ALL or Nothing
CREATE INDEX emp$sal ON emp(sal); SELECT * FROM emp WHERE sal > (SELECT MAX(AVG(sal)) FROM emp GROUP BY deptno);
-------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Time | -------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 87 | 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 87 | 00:00:01 | |* 2 | INDEX RANGE SCAN | EMP$SAL | 1 | | 00:00:01 | | 3 | SORT AGGREGATE | | 1 | 26 | 00:00:01 | | 4 | SORT GROUP BY | | 1 | 26 | 00:00:01 | | 5 | TABLE ACCESS FULL | EMP | 14 | 364 | 00:00:01 | --------------------------------------------------------------------------
24
25
26
The commission values are lost due to the implicit equality test on NULL
27
28
29
Weird CASEs
Table tc1 has no rows CREATE TABLE tc1 (col1 NUMBER); SELECT (CASE WHEN COUNT(*) = 0 THEN 10 ELSE 12 END) FROM tc1; (CASEWHENCOUNT(*)=0THEN10ELSE12END) ----------------------------------10 SELECT (CASE WHEN COUNT(*) = 0 THEN 10 ELSE 10 END) FROM tc1;
no rows selected
31
Query fails on first salesman SELECT ename ,CASE WHEN job != 'SALESMAN' THEN job ELSE TO_CHAR(1/0) END AS not_selling FROM emp ERROR: ORA-01476: divisor is equal to zero no rows selected
33
34
D1 --------02-SEP-00 09-SEP-99
DUMP_D1 -------------------------------Typ=13 Len=8: 208,7,9,2,0,0,0,0 Typ=13 Len=8: 51,8,1,1,0,0,0,0 NULL 29-FEB-00 Typ=13 Len=8: 208,7,2,29,0,0,0,0 01-OCT-00 Typ=13 Len=8: 208,7,10,1,0,0,0,0
35
36
38
DENSE_RANKM
DENSE_RANKM Seems to cause trouble at the moment
SELECT DENSE_RANKM(ename) OVER (ORDER BY sal) FROM emp; ERROR at line 1: ORA-03113: end-of-file on communication channel
39
MERGE$ACTIONS
Compares two strings (or numbers or dates) Reports as a B', any characters in the first string that differ from the corresponding character in the second string
SELECT MERGE$ACTIONS(string1,string2) FROM dual;
SELECT sysdate ,MERGE$ACTIONS(sysdate, sysdate-1) ,MERGE$ACTIONS(sysdate,sysdate + 1) FROM dual; SYSDATE MERGE$ACT MERGE$ACT --------- --------- --------31-JAN-10 3B-JAN-10 B1-BBB-10
40
SYS_OP_DISTINCT
SELECT col1 ,col2 ,sys_op_distinct(col1, col2) FROM t; COL1 COL2 SYS_OP_DISTINCT(COL1,COL2) ---------- ---------- -------------------------1 1 0 1 2 1 2 1 1 2 2 0 1
41
REVERSE
SELECT ename ,REVERSE(ename) FROM emp;
ENAME ---------SMITH ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER REVERSE(EN ---------HTIMS NELLA DRAW SENOJ NITRAM EKALB KRALC TTOCS GNIK RENRUT SMADA SEMAJ DROF RELLIM
SELECT empno ,utl_raw.cast_to_varchar2( utl_raw.reverse( utl_raw.cast_to_raw(empno))) rev_num ,ename ,utl_raw.cast_to_varchar2( utl_raw.reverse( utl_raw.cast_to_raw(ename))) rev_char FROM emp;
EMPNO ----7369 7499 7521 7566 7654 7698 7782 7788 7839 7844 7876 7900 7902 7934
REV_NUM ------9637 9947 1257 6657 4567 8967 2877 8877 9387 4487 6787 0097 2097 4397
ENAME ---------SMITH ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER
REV_CHAR -------HTIMS NELLA DRAW SENOJ NITRAM EKALB KRALC TTOCS GNIK RENRUT SMADA SEMAJ DROF RELLIM
42
OVERLAPS
Takes two periods in time and checks for any overlap between them Not entirely reliable, for instance (TRUNC(sysdate),TRUNC(sysdate) + 1)
43
SYS_OP_MAP_NONNULL
How do employees salaries differ from the average salary of those employees who report to the same manager?
SELECT r.ename ,r.mgr ,r.sal ,ROUND(AVG(g.sal)) avgsal ,r.sal-ROUND(AVG(g.sal)) diff FROM emp r ,emp g WHERE r.mgr = g.mgr(+) GROUP BY r.mgr ,r.ename ,r.sal ORDER BY r.mgr;
The outer join is necessary so that the managerless KING is included However, KINGs average values are left as NULL
44
SYS_OP_MAP_NONNULL
ENAME MGR SAL AVGSAL DIFF ---------- ---------- ---------- ---------- ---------FORD 7566 3000 3000 0 SCOTT 7566 3000 3000 0 ALLEN 7698 1600 1310 290 JAMES 7698 950 1310 -360 MARTIN 7698 1250 1310 -60 TURNER 7698 1500 1310 190 WARD 7698 1250 1310 -60 MILLER 7782 1300 1300 0 ADAMS 7788 1100 1100 0 BLAKE 7839 2850 2758 92 CLARK 7839 2450 2758 -308 JONES 7839 2975 2758 217 SMITH 7902 800 800 0 KING 5000
SYS_OP_MAP_NONNULL can be used to have a NULL match a NULL There are many SYS_OP functions
Carl Dudley University of Wolverhampton 45
SYS_OP_MAP_NONNULL
SELECT r.ename ,r.mgr ,r.sal ,ROUND(AVG(g.sal)) avgsal ,r.sal-ROUND(AVG(g.sal)) diff FROM emp r ,emp g WHERE SYS_OP_MAP_NONNULL(r.mgr) = SYS_OP_MAP_NONNULL(g.mgr) GROUP BY r.mgr ,r.ename ,r.sal ORDER BY r.mgr; ENAME MGR SAL AVGSAL DIFF ---------- ---------- ---------- ---------- ---------FORD 7566 3000 3000 0 SCOTT 7566 3000 3000 0 : : : : : MILLER 7782 800 1300 -500 KING Null 5000 5000 0
Carl Dudley University of Wolverhampton
46
SYS_OP_MAP_NONNULL vs LNNVL
We can also use LNNVL to achieve the same output SELECT r.ename ,r.mgr ,r.sal ,ROUND(AVG(g.sal)) avgsal ,r.sal-ROUND(AVG(g.sal)) diff FROM emp r emp g WHERE LNNVL(r.mgr = g.mgr) GROUP BY r.mgr ,r.ename ,r.sal ORDER BY r.mgr; Of course, a more conventional method would be to use NVL(r.mgr,-1) = NVL(g.mgr,-1)
47
ADJ_DATE
Adjusts timestamps to dates? CREATE TABLE t(dcol TIMESTAMP, dcol2 date); INSERT INTO t VALUES (systimestamp,sysdate); SELECT dcol TS ,ADJ_DATE(dcol) ADJ_DATE_TS ,systimestamp ,TO_CHAR(dcol) TO_CHAR ,ADJ_DATE(dcol2) ADJ_DATE_DATE FROM t; TS : ADJ_DATE_TS : SYSTIMESTAMP : TO_CHAR : ADJ_DATE_DATE : 05-MAR-10 05-MAR-10 05-MAR-10 05-MAR-10 05-MAR-10 11.08.14.868000 11.08.15 11.08.14.883000 +00:00 11.08.14.868000
48
COLLECT (Oracle10g)
SELECT deptno ,COLLECT(ename) AS emps FROM emp GROUP BY deptno;
DEPTNO -----10 20 EMPS -----------------------------------------------SYSTPL9nnPGZ5R/m5SYax8mMjpQ==('CLARK','KING','MILLER') SYSTPL9nnPGZ5R/m5SYax8mMjpQ==('SMITH','FORD','ADAMS' ,'SCOTT','JONES') 30 SYSTPL9nnPGZ5R/m5SYax8mMjpQ==('ALLEN', 'BLAKE','MARTIN' ,'TURNER','JAMES','WARD')
Oracle creates a system-generated type on each hard parse Retained in the shared pool and seen in all_types
49
50
SYS_OP_ Functions
SYS_OP_ALEXPCOL SYS_OP_ATG SYS_OP_BL2R SYS_OP_BLOOM_FILTER SYS_OP_BLOOM_FILTER_LIST SYS_OP_C2C SYS_OP_CEG SYS_OP_CL2C SYS_OP_COMBINED_HASH SYS_OP_COMP SYS_OP_CONVERT SYS_OP_COUNTCHG SYS_OP_CSCONV SYS_OP_CSCONVTEST SYS_OP_CSR SYS_OP_CSX_PATCH SYS_OP_CSX_UPD SYS_OP_DECOMP SYS_OP_DESCEND SYS_OP_DUMP SYS_OP_GROUPING SYS_OP_LBID SYS_OP_LOBLOC2BLOB SYS_OP_LOBLOC2CLOB SYS_OP_LOBLOC2ID SYS_OP_LOBLOC2NCLOB SYS_OP_LOBLOC2TYP SYS_OP_LOBSNAP SYS_OP_LSVI SYS_OP_LVL SYS_OP_MAKEOID SYS_OP_MAP_NONNULL SYS_OP_MSR SYS_OP_NICOMBINE SYS_OP_NIEXTRACT SYS_OP_NIX SYS_OP_NUMTORAW SYS_OP_OIDVALUE SYS_OP_OPNSIZE SYS_OP_PAR SYS_OP_PARGID SYS_OP_PIVOT SYS_OP_R2O SYS_OP_RAWTONUM SYS_OP_RMTD SYS_OP_RPB SYS_OP_TOSETID SYS_OP_TRTB SYS_OP_UNDESCEND SYS_OP_VECAND SYS_OP_VECBIT SYS_OP_VECOR SYS_OP_VECXOR SYS_OP_VERSION SYS_OP_VVD SYS_OP_XPTHATG SYS_OP_XPTHIDX SYS_OP_XPTHOP SYS_OP_XTXT2SQLT
51
52
NVL2
Decodes non-NULL and NULL values SELECT ename ,job ,NVL2(comm,'Has commission' ,'No commission') AS Commission? FROM emp WHERE deptno = 30; ENAME ---------ALLEN WARD MARTIN BLAKE TURNER JAMES JOB --------SALESMAN SALESMAN SALESMAN MANAGER SALESMAN CLERK Commission? -------------Has commission Has commission Has commission No commission Has commission No commission
53
NULLIF
Takes two arguments [NULLIF(arg1,arg2)] and returns NULL if the first argument equals the second Find who is in a department different to that of their manager
SELECT w.ename w_ename ,w.empno w_empno ,w.deptno w_deptno ,m.ename m_ename ,m.deptno m_deptno ,NULLIF(m.deptno,w.deptno) diff_deptno FROM emp w ,emp m WHERE w.mgr = m.empno(+);
54
NULLIF (continued)
W_ENAME W_EMPNO W_DEPTNO M_ENAME M_DEPTNO DIFF_DEPTNO ------- ------- -------- ------- -------- ----------SCOTT 7788 20 JONES 20 FORD 7902 20 JONES 20 ALLEN 7499 30 BLAKE 30 WARD 7521 30 BLAKE 30 JAMES 7900 30 BLAKE 30 TURNER 7844 30 BLAKE 30 MARTIN 7654 30 BLAKE 30 MILLER 7934 10 CLARK 10 ADAMS 7876 20 SCOTT 20 JONES 7566 20 KING 10 10 CLARK 7782 10 KING 10 BLAKE 7698 30 KING 10 10 SMITH 7369 20 FORD 20 KING 7839 10
55
COALESCE
A standard generalization of the NVL function that returns the first non-null expression in the list COALESCE(expr_1,..., expr_n)
SELECT empno ,ename, ,COALESCE(office_telno ,mobile_telno ,works_telno ,office_faxno) the_contact_number FROM employee_contacts;
56
57
58
PIVOT/UNPIVOT
There is an increasing need to present data in different orientations Oracle 11g has a new construct to handle denormalised data PIVOT can be used to normalise a set of data UNPIVOT can be used to present data in a denormalised format
SELECT * FROM (SELECT deptno,job,sal FROM emp) e PIVOT(SUM(sal) FOR job IN ('CLERK' CLERK,'SALESMAN' SALESMAN, 'MANAGER' MANAGER,'ANALYST' ANALYST, 'PRESIDENT' PRESIDENT)) ORDER BY deptno; DEPTNO CLERK SALESMAN MANAGER ANALYST PRESIDENT ---------- ---------- ---------- ---------- ---------- ---------10 1300 2450 5000 20 1900 2975 6000 30 950 5600 2850
59
SELECT * FROM (SELECT deptno,job,sal FROM emp) e PIVOT(SUM (sal) FOR job IN (SELECT DISTINCT job FROM emp)) ORDER BY deptno; PIVOT(SUM(SAL) FOR job IN (SELECT DISTINCT job FROM emp)); * ERROR at line 2: ORA-00936: missing expression
60
Unless the XML keyword is used The output then appears in XML
Carl Dudley University of Wolverhampton 61
DEPTNO CLERK SALESMAN MANAGER ANALYST PRESIDENT ---------- ---------- ---------- ---------- ---------- ---------10 1300 2450 5000 20 1900 2975 6000 30 950 5600 2850
SELECT * FROM emppiv UNPIVOT INCLUDE NULLS (sal FOR job IN (CLERK,SALESMAN, MANAGER,ANALYST,PRESIDENT))
Pivoted Table
DEPTNO ---------10 10 10 10 10 20 20 20 20 20 30 30 30 30 30
JOB SAL --------- ---------CLERK 1300 SALESMAN MANAGER 2450 ANALYST PRESIDENT 5000 CLERK 1900 SALESMAN MANAGER 2975 ANALYST 6000 PRESIDENT CLERK 950 SALESMAN 5600 MANAGER 2850 ANALYST PRESIDENT
SELECT * FROM emppiv UNPIVOT (sal FOR job IN (CLERK,SALESMAN, MANAGER,ANALYST,PRESIDENT)) DEPTNO ---------10 10 10 20 20 20 30 30 30 JOB SAL --------- ---------CLERK 1300 MANAGER 2450 PRESIDENT 5000 CLERK 1900 MANAGER 2975 ANALYST 6000 CLERK 950 SALESMAN 5600 MANAGER 2850
9 rows selected.
LISTAGG
Show a list of items belonging to a group within a single row SELECT table_name ,index_name ,LISTAGG(column_name,;) WITHIN GROUP ( ORDER BY column_position) Column List FROM user_ind_columns GROUP BY table_name ,index_name; TABLE_NAME -----------EMP PROJ_ASST DEPT INDEX_NAME -----------------EMP_PK SYS_C0011223 DEPT$DIVNO_DEPTNO Column List ----------------------EMPNO PROJNO;EMPNO;START_DATE DIVNO;DEPTNO
63
64
66
A Better Solution?
This query finds an employee at any position in the hierarchy regardless of the data pattern performs reasonably well
SELECT e1.ename ,e1.sal ,&&position Position FROM emp e1 WHERE (e1.sal ,&&position) = (SELECT MIN(e2.sal) ,COUNT(e3.empno) + 1 FROM emp e2 ,emp e3 WHERE e2.sal >= e1.sal AND e3.empno(+) = e2.empno AND e3.sal(+) <> e1.sal);
67
An Explanation?
Examine subquery processing with a received value of 3000
SELECT e2.empno AS e2empno ,e2.sal AS e2sal ,e3.empno AS e3empno ,e3.sal AS e3sal FROM emp e2 ,emp e3 WHERE e2.sal >= 3000 AND e3.empno(+) = e2.empno AND e3.sal(+) <> 3000; E2EMPNO E2SAL E3EMPNO E3SAL ------- --------- --------- --------7839 5000 7839 5000 7788 3000 7902 3000
The empno and sal values in e3 are set to NULL only where the salary matches the incoming value NULL values are not COUNTed
Carl Dudley University of Wolverhampton 68
An Explanation (continued)?
SELECT MIN(e2.sal) AS Minsal_e2 ,COUNT(e3.empno) + 1 AS Countempno_e3 FROM emp e2 ,emp e3 WHERE e2.sal >= 3000 AND e3.empno(+) = e2.empno AND e3.sal(+) <> 3000;
MINSAL_E2 COUNTEMPNO_E3 --------- ------------3000 2 So, if e1.sal is 3000, this subquery returns 3000 for the salary value and 2 for the position in the hierarchy What would be the result if : position = 3 ? position = 4 ?
Carl Dudley University of Wolverhampton 69
An Explanation (continued)?
Remember, we have to cater for people on equal salary levels above our chosen position in the hierarchy SALARY POSITION ------ -------5000 1 3000 2 3000 2 (3) 2975 4 2850 5 2700 6 2700 6 (7) 2700 6 (8) 2500 9 SALARY LEVEL -------------1 2 2 3 4 5 5 5 6
70
SELECT ename ,sal FROM emp x WHERE &position - 1 = (SELECT COUNT(*) FROM emp y WHERE y.sal > x.sal)
With position = 4
With position = 4
72
73
Analytic Functions
SELECT deptno ,ename ,sal ,RANK() OVER (ORDER BY sal DESC) AS R_sal ,DENSE_RANK() OVER (ORDER BY sal DESC) AS Dense_R_sal FROM emp
DEPTNO -----10 20 20 20 30 10 30 30 10 30 30 20 30 20 ENAME SAL R_SQL DENSE_R_SAL ---------- ---------- ------- ----------KING 5000 1 1 FORD 3000 2 2 SCOTT 3000 2 2 JONES 2975 4 3 BLAKE 2850 5 4 CLARK 2450 6 5 ALLEN 1600 7 6 TURNER 1500 8 7 MILLER 1300 9 8 WARD 1250 10 9 MARTIN 1250 10 9 ADAMS 1100 12 10 JAMES 950 13 11 SMITH 800 14 12
Carl Dudley University of Wolverhampton 74
75
Numbers to Characters
Julian Dates can be used to show numerical values as English text Show the total annual salary bill in text SELECT TO_CHAR(TO_DATE(SUM(sal)*12,'J'),'Jsp') ||' Dollars' AS Total_Annual_Salary_Bill
FROM emp
76
Reversibility
Find departments with at least two salesmen SELECT deptno FROM emp WHERE job = SALESMAN GROUP BY deptno HAVING COUNT(*) >= 2; DEPTNO -----30 Find departments with less than two salesmen SELECT deptno FROM emp WHERE job = SALESMAN GROUP BY deptno HAVING COUNT(*) < 2;
no rows selected.
Carl Dudley University of Wolverhampton 77
Reversibility (continued)
Departments with less than two salesmen fixed with the following query SELECT DISTINCT e1.deptno FROM emp e1 WHERE (SELECT COUNT(*) FROM emp e2 WHERE job = SALESMAN AND e2.deptno = e1.deptno) < 2;
DEPTNO -----10 20
78
Reversibility (continued)
Departments that pay a total of $3000 or more to salesmen SELECT DISTINCT e1.deptno FROM emp e1 WHERE (SELECT SUM(e2.sal) FROM emp e2 WHERE e2.job = SALESMAN AND e2.deptno = e1.deptno) >= 3000; DEPTNO -----30 And those that do not SELECT DISTINCT e1.deptno FROM emp e1 WHERE (SELECT SUM(e2.sal) FROM emp e2 WHERE e2.job = SALESMAN AND e2.deptno = e1.deptno) < 3000; no rows selected.
Carl Dudley University of Wolverhampton
[ ERROR? ]
79
Reversibility (continued)
Fixed with following query SELECT DISTINCT e1.deptno FROM emp e1 WHERE (SELECT NVL(SUM(e2.sal),0) FROM emp e2 WHERE e2.job = SALESMAN AND e2.deptno = e1.deptno) <= 3000; DEPTNO -----10 20
80
DUMMY ----X
SELECT COUNT(*) FROM COUNT(*) -------2 SELECT MAX(dummy) FROM dual;
DUMMY ----Z
82
Median (deptno) = 30
83
84
DEPTNO -----10 20 30 40 50
85
Returns the modal (most frequently occurring) value in a column If there are ties it returns only the first one found SELECT STATS_MODE(job) ,STATS_MODE(deptno) ,STATS_MODE(empno) FROM emp; STATS_MODE(JOB) STATS_MODE(DEPTNO) STATS_MODE(EMPNO) --------------- ------------------ ----------------CLERK 30 7369
86
SQL*Plus Features
ROLL #
SQL> SELECT empno,ename 2 #DESC emp Name -----------------------------------EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO 2 hiredate,sal 3 FROM emp 4 WHERE ename = 'KING'; EMPNO HIREDATE SAL ------ ---------- ----7839 KING 5000
Null? Type -------- -----------NOT NULL NUMBER(4) VARCHAR2(10) VARCHAR2(9) NUMBER(4) DATE NUMBER(7,2) NUMBER(7,2) NOT NULL NUMBER(2)
87