Sie sind auf Seite 1von 88

SQL Weird and Wonderful Language Carl Dudley

University of Wolverhampton, UK

UKOUG Committee Oracle ACE Director


carl.dudley@wlv.ac.uk
Carl Dudley University of Wolverhampton 1

Introduction
Working with Oracle since 1986
Oracle DBA - OCP Oracle7, 8, 9, 10 Oracle DBA of the Year 2002

Oracle ACE Director


Beta tester Oracle8, 9, 10, 11 Regular Presenter at Oracle Conferences

Consultant and Trainer


Technical Editor for a number of Oracle texts UK Oracle User Group Director

Member of IOUC
Day job University of Wolverhampton, UK
Carl Dudley University of Wolverhampton 2

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

The Sample Employee Data


EMPNO ----7839 7902 7788 7566 7698 7782 7499 7844 7934 7521 7654 7876 7900 7369 ENAME -----KING FORD SCOTT JONES BLAKE CLARK ALLEN TURNER MILLER WARD MARTIN ADAMS JAMES SMITH JOB --------PRESIDENT ANALYST ANALYST MANAGER MANAGER MANAGER SALESMAN SALESMAN CLERK SALESMAN SALESMAN CLERK CLERK CLERK MGR HIREDATE ---- --------17-NOV-81 7566 03-DEC-81 7566 09-DEC-82 7839 02-APR-81 7839 01-MAY-81 7839 09-JUN-81 7698 20-FEB-81 7698 08-SEP-81 7782 23-JAN-82 7698 22-FEB-81 7698 28-SEP-81 7788 12-JAN-83 7698 03-DEC-81 7902 17-DEC-80 SAL COMM DEPTNO ---- ---- -----5000 10 3000 20 3000 20 2975 20 2850 30 2450 10 1600 300 30 1500 0 30 1300 10 1250 500 30 1250 1400 30 1100 20 950 30 800 20

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

Scoping in SQL (continued)


SELECT ename ,job ,deptno ,sal FROM emp WHERE deptno = 10 AND job IN (SELECT job FROM dept WHERE deptno = (SELECT deptno FROM dept WHERE dname = 'SALES')) ENAME ---------CLARK KING MILLER JOB DEPTNO SAL --------- --------- --------MANAGER 10 2450 PRESIDENT 10 5000 CLERK 10 1300 dept table DEPTNO DNAME SAL ------ --------- --------10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON

Carl Dudley University of Wolverhampton

Scoping in SQL (continued)


SELECT ename FROM emp WHERE job IN (SELECT job FROM dept)
ENAME ---------SMITH ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER

SELECT ename FROM emp WHERE job IN (SELECT dept.job FROM dept) * ERROR at line 1: ORA-00904: "DEPT.JOB": invalid identifier

Carl Dudley University of Wolverhampton

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

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.

Carl Dudley University of Wolverhampton

Aggregate Functions and NULLs


SELECT COUNT(sal) FROM emp WHERE deptno = 99;

Fun with nulls

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.

Carl Dudley University of Wolverhampton

10

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

11

NOT IN vs NOT EXISTS


There are eight employees who do not manage anyone else

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

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

NOT IN vs NOT EXISTS (continued)


Change the mgr value for KING UPDATE emp SET mgr = 9999 WHERE ename = KING; SELECT * FROM emp WHERE empno NOT IN (SELECT mgr FROM emp); 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

NOT IN is affected by NULLs NOT IN is equivalent to != ALL


Carl Dudley University of Wolverhampton

13

NOT IN vs NOT EXISTS (continued)


The equivalent NOT EXISTS construct is resistant to the presence of NULLs

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

Carl Dudley University of Wolverhampton

14

Departments with no Employees


SELECT * FROM dept WHERE deptno NOT IN (SELECT deptno FROM emp);
SELECT * FROM dept x WHERE NOT EXISTS (SELECT 1 FROM emp y WHERE y.deptno = x.deptno);

DEPTNO DNAME LOC ------ ---------- -----40 OPERATIONS BOSTON

Carl Dudley University of Wolverhampton

15

No Index and no NOT NULL Constraint on emp.deptno


Oracle Version
8i

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

NOT EXISTS plan


SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP
16

9i

10g

11g

Carl Dudley University of Wolverhampton

NOT NULL constraint on emp.deptno


Oracle Version 8i 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 SNA TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP NOT EXISTS plan SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT TABLE ACCESS FULL EMP
17

9i

10g

11g

Carl Dudley University of Wolverhampton

Index on emp.deptno, no NOT NULL constraint


Oracle Version 8i 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 NOT EXISTS plan SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT INDEX RANGE SCAN EMP$DEPTNO SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT INDEX RANGE SCAN EMP$DEPTNO SELECT STATEMENT NESTED LOOPS ANTI TABLE ACCESS FULL DEPT INDEX RANGE SCAN EMP$DEPTNO SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT INDEX FAST FULL SCAN EMP$DEPTNO
18

9i

10g

11g

Carl Dudley University of Wolverhampton

Index and NOT NULL Constraint on emp.deptno


Version 8i NOT IN plan SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT INDEX RANGE SCAN EMP$DEPTNO SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT INDEX FAST FULL SCAN EMP$DEPTNO SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT INDEX FAST FULL SCAN EMP$DEPTNO NOT EXISTS plan SELECT STATEMENT FILTER TABLE ACCESS FULL DEPT INDEX RANGE SCAN EMP$DEPTNO SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT INDEX RANGE SCAN EMP$DEPTNO SELECT STATEMENT HASH JOIN ANTI TABLE ACCESS FULL DEPT INDEX FAST FULL SCAN EMP$DEPTNO

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

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

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

ANYthing Goes (continued)


SELECT e1.ename ,e1.sal FROM emp e1 WHERE NOT(e1.sal > ANY(SELECT e2.sal FROM emp e2 WHERE e2.deptno = 99)) ENAME SAL ---------- --------SMITH 800 ALLEN 1600 WARD 1250 JONES 2975 MARTIN 1250 BLAKE 2850 CLARK 2450 SCOTT 3000 KING 5000 TURNER 1500 ADAMS 1100 JAMES 950 FORD 3000 MILLER 1300
Carl Dudley University of Wolverhampton 22

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 | --------------------------------------------------------------------------

Carl Dudley University of Wolverhampton

24

ALL or Nothing (continued)


The equivalent ALL does not use the index SELECT * FROM emp WHERE sal > ALL (SELECT AVG(sal) FROM emp GROUP BY deptno);
-----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 13 | 1131 | 7 (15)| 00:00:01 | |* 1 | FILTER | | | | | | | 2 | TABLE ACCESS FULL | EMP | 14 | 1218 | 3 (0)| 00:00:01 | |* 3 | FILTER | | | | | | | 4 | HASH GROUP BY | | 14 | 364 | 4 (25)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP | 14 | 364 | 3 (0)| 00:00:01 | ------------------------------------------------------------------------------

Carl Dudley University of Wolverhampton

25

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

26

CASE and NULLs


SELECT ename ,comm ,CASE comm WHEN NULL THEN 'N/A' END AS CASE_COMM FROM emp WHERE deptno = 30; ENAME ---------ALLEN WARD MARTIN BLAKE TURNER JAMES COMM CASE_COMM --------- --------300 500 1400 0

The commission values are lost due to the implicit equality test on NULL

Carl Dudley University of Wolverhampton

27

CASE and NULLs (continued)


SELECT ename ,comm ,CASE comm WHEN NULL THEN 'N/A' ELSE TO_CHAR(comm) END AS CASE_COMM FROM emp WHERE deptno = 30; ENAME COMM CASE_COMM ---------- ---------- --------ALLEN 300 300 WARD 500 500 MARTIN 1400 1400 BLAKE TURNER 0 0 JAMES With the ELSE clause added, the NULLs still do not appear as N/A Note the datatype of CASE_COMM

Carl Dudley University of Wolverhampton

28

CASE and NULLs (continued)


SELECT ename ,comm ,CASE WHEN comm IS NULL THEN 'N/A' ELSE TO_CHAR(COMM) END AS CASE_COMM FROM emp WHERE deptno = 30; ENAME COMM CASE_COMM ---------- ---------- --------ALLEN 300 300 WARD 500 500 MARTIN 1400 1400 BLAKE N/A TURNER 0 0 JAMES N/A The searched CASE is resistant to NULLs

Carl Dudley University of Wolverhampton

29

CASE in ORDER BY Clauses


The PRESIDENT always comes out on top SELECT * FROM empcopy ORDER BY CASE job WHEN 'PRESIDENT' THEN '1' ELSE job END; EMPNO ----7839 7788 7902 7369 : ENAME ---------KING SCOTT FORD SMITH : JOB --------PRESIDENT ANALYST ANALYST CLERK : MGR HIREDATE ---- --------17-NOV-81 7566 19-APR-87 7566 03-DEC-81 7902 17-DEC-80 : : SAL COMM DEPTNO ---- ---- -----5000 10 3000 20 3000 20 800 20 : :

SELECT * FROM emp ORDER BY DECODE(job,'PRESIDENT','1',job);


Carl Dudley University of Wolverhampton 30

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

Carl Dudley University of Wolverhampton

31

Causing Queries to Fail in Certain Cases


A divide by zero can be used in CASE Deliberately fail the query if a salesman is found SELECT ename ,CASE WHEN job != 'SALESMAN' THEN job ELSE TO_CHAR(1/0) END AS not_selling FROM emp WHERE deptno != 30; ENAME ---------SMITH JONES CLARK SCOTT KING ADAMS FORD MILLER NOT_SELLING ---------------------------------------CLERK MANAGER MANAGER ANALYST PRESIDENT CLERK ANALYST CLERK
Carl Dudley University of Wolverhampton 32

Causing Queries to Fail in Certain Cases

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

Carl Dudley University of Wolverhampton

33

DECODE and Datatypes


DECODE returns the datatype of its first return item SELECT ename ,d1 ,DUMP(DECODE(d1, '01-JAN-99','01-JAN-99', '09-SEP-99',TO_DATE('01-JAN-99','DD-MON-YY') ,d1)) AS dump_d1 FROM testdate; ENAME ----BROWN SMITH COX ADAMS SCOTT D1 --------02-SEP-00 09-SEP-99 DUMP_D1 --------------------------------------Typ=1 Len=9: 48,50,45,83,69,80,45,48,48 Typ=1 Len=9: 48,49,45,74,65,78,45,57,57 NULL 29-FEB-00 Typ=1 Len=9: 50,57,45,70,69,66,45,48,48 01-OCT-00 Typ=1 Len=9: 48,49,45,79,67,84,45,48,48

Carl Dudley University of Wolverhampton

34

DECODE and Datatypes (continued)


SELECT ename ,d1 ,DUMP(DECODE(d1, --'01-JAN-99','01-JAN-99', '09-SEP-99',TO_DATE('01-JAN-99','DD-MON-YY') ,d1)) AS dump_d1 FROM testdate;

ENAME ----BROWN SMITH COX ADAMS SCOTT

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

Carl Dudley University of Wolverhampton

35

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

36

CASTing with GROUP BY


The ename column in castemp has 4-character strings BBBA, BBBC etc. SELECT CAST(ename AS VARCHAR2(3)) FROM castemp; CAS --BBB BBB BBB SELECT CAST(ename AS VARCHAR2(3)) FROM castemp GROUP BY CAST(ename AS VARCHAR2(4)) VARCHAR2(4)); HAVING CAST(ename) AS VARCHAR2(3)) = 'BBB'; CAST ---no rows selected. BBBA BBBB BBBE
Carl Dudley University of Wolverhampton 37

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

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;

String 1 -------ABC ABC ABCDDD 1234 SYSDATE 12645

String 2 ---------ABD ABC ABCEDD 1264 SYSDATE+35 12681

Result from merge$actions ------------------------ABB ABC ABCBDD 12B4 BB-BAB-10 126BB

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

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

OVERLAPS
Takes two periods in time and checks for any overlap between them Not entirely reliable, for instance (TRUNC(sysdate),TRUNC(sysdate) + 1)

is not seen as overlapping with


(TRUNC(sysdate),TRUNC(sysdate) + 1) SELECT NVL2(AVG(1),'yes','no') AS "overlap?" FROM dual WHERE (ADD_MONTHS(sysdate, -18), TO_DATE('01-APR-2011')) OVERLAPS (sysdate - 400, INTERVAL '3' MONTH); OVERLAP? -------YES

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

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)

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

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

These types can be dropped DROP TYPE "SYSTPL9nnPGZ5R/m5SYax8mMjpQ==";

Carl Dudley University of Wolverhampton

49

COLLECT with User-defined Type


CREATE OR REPLACE TYPE en_typ AS TABLE OF VARCHAR2(20); /
SELECT deptno ,CAST(COLLECT(ename) AS en_typ) EMPS FROM emp GROUP BY deptno;
DEPTNO -----10 20 30 EMPS -----------------------------------------------EN_TYP('CLARK','KING','MILLER') EN_TYP('SMITH','FORD','ADAMS','SCOTT','JONES') EN_TYP('ALLEN', 'BLAKE','MARTIN','TURNER','JAMES','WARD')

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

51

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

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(+);

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

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;

Carl Dudley University of Wolverhampton

56

Generating Consecutive Dates


Recursive queries can be used to generate series of dates
VARIABLE x VARCHAR2(20); EXEC :x := 'JAN-2008'; WITH DATA AS (SELECT LEVEL L FROM dual CONNECT BY LEVEL <= TO_NUMBER( TO_CHAR( LAST_DAY( TO_DATE(:x ,'mon-yyyy') ),'dd ) ) ) SELECT TO_DATE(:x,'mon-yyyy')+L-1 FROM data;

TO_DATE(: --------01-JAN-08 02-JAN-08 03-JAN-08 : : : 30-JAN-08 31-JAN-08

Carl Dudley University of Wolverhampton

57

Recursive Subquery Factoring


Generating consecutive dates with WITH A new 11g R2 construct can also be used to generate dates WITH data(r) AS (SELECT 1 r FROM dual UNION ALL SELECT r + 1 FROM data WHERE r < 5) SELECT r, SYSDATE + r FROM data; R ---1 2 3 4 5 SYSDATE + R ----------01-AUG-2011 02-AUG-2011 03-AUG-2011 04-AUG-2011 05-AUG-2011

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

59

Generating the 'Normalised' Columns


Subqueries cannot be used to generate the columns unless the XML keyword is used here However, the output is in XML

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

Carl Dudley University of Wolverhampton

60

The PIVOT Clause in Oracle 11g


More intuitive than using DECODE
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

But subqueries are not allowed to generate the values


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

Unless the XML keyword is used The output then appears in XML
Carl Dudley University of Wolverhampton 61

The UNPIVOT Clause in Oracle 11g


SELECT * FROM emppiv;

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.

15 rows selected. Carl Dudley University of Wolverhampton 62

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

Carl Dudley University of Wolverhampton

63

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

64

Finding The Second Most Highly Salaried Employee


A first simple attempt SELECT ename ,sal FROM emp WHERE sal = (SELECT MAX(sal) FROM emp WHERE sal < (SELECT MAX(sal) FROM emp));
ENAME SAL ---------- ---SCOTT 3000 FORD 3000 But this works only because there is just one person with a salary equal to the maximum Does not handle ties for first place
Carl Dudley University of Wolverhampton 65

A Suggested Solution From Oracle


SELECT ename ,sal FROM emp WHERE sal IN (SELECT MAX(e1.sal) FROM emp e1 WHERE EXISTS (SELECT NULL FROM emp e2 WHERE e2.sal >= e1.sal HAVING COUNT(sal) > &n-1)); With n = 2 ENAME ---------SCOTT FORD SAL ------3000 3000 With n = 3 ENAME ---------SCOTT FORD SAL ------3000 3000

Carl Dudley University of Wolverhampton

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);

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

70

The Final Solution?


This query finds an employee at any position in the hierarchy regardless of the data pattern. performs really well - only a two table join

SELECT ename ,sal FROM emp x WHERE &position - 1 = (SELECT COUNT(*) FROM emp y WHERE y.sal > x.sal)

With position = 4

ENAME SAL ---------- --------JONES 2975


71

Carl Dudley University of Wolverhampton

Finding the Top Dogs


The previous query can be adapted to find employees above a specified position in terms of salary SELECT ename ,sal FROM emp x WHERE &position - 1 > (SELECT COUNT(*) FROM emp y WHERE y.sal > x.sal) ORDER BY x.sal DESC; ENAME SAL ---------- --------KING 5000 SCOTT 3000 FORD 3000

With position = 4

Carl Dudley University of Wolverhampton

72

Fourth Highest using In-line View


SELECT deptno ,ename ,sal ,Salrank FROM (SELECT deptno ,ename ,sal ,RANK() OVER (ORDER BY sal DESC) AS Salrank FROM emp) WHERE Salrank = 4; DEPTNO ENAME SAL SALRANK ------ ------- ----- -------20 JONES 2975 4

Carl Dudley University of Wolverhampton

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

SQL Weird and Wonderful Language


Coping with Scoping in SQL Aggregate Functions NOT IN vs NOT EXISTS ANY and ALL or nothing The case for CASE CASTaway
Undocumented features scary creatures New or less well known features Who's in second place with SQL Miscellaneous other stuff
Carl Dudley University of Wolverhampton

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

TOTAL_ANNUAL_SALARY_BILL -------------------------------------------------------Three Hundred Forty-Eight Thousand Three Hundred Dollars

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

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

Carl Dudley University of Wolverhampton

80

The DUAL Anomaly


INSERT INTO dual VALUES(Z); SELECT * FROM dual; SELECT * FROM dual WHERE dummy ='Z'; DUMMY ----Z SELECT * FROM dual WHERE dummy <> X; dual; DUMMY ----X SELECT * FROM dual ORDER BY dummy DESC; DUMMY ----Z SELECT * FROM dual ORDER BY dummy; DUMMY ----X

DUMMY ----X
SELECT COUNT(*) FROM COUNT(*) -------2 SELECT MAX(dummy) FROM dual;

DUMMY ----Z

ROWIDs and DELETEs are also interesting


Carl Dudley University of Wolverhampton 81

Multiple Rows in DUAL


INSERT INTO dual VALUES(Z);
CREATE OR REPLACE FUNCTION next_friday RETURN DATE IS n_f DATE; BEGIN n_f := NEXT_DAY(sysdate,'FRIDAY'); RETURN(n_f); END;
SELECT next_friday FROM dual * ERROR at line 1: ORA-01422: exact fetch returns more than requested number of rows ORA-06512: at "SYS.STANDARD", line 1014 ORA-06512: at "SYS.NEXT_FRIDAY", line 6 ORA-06512: at line 1

Similar problems occur with sequences

Carl Dudley University of Wolverhampton

82

Finding the Median


Finding the MEDIAN of a set of values has not been easy The MEDIAN of a set is the value which has an equal number of items having values above and below it in that set DEPTNO DNAME SAL ------ --------- --------10 ACCOUNTING NEW YORK Median (deptno) = 25 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON DEPTNO -----10 20 30 40 50 DNAME SAL --------- --------ACCOUNTING NEW YORK RESEARCH DALLAS SALES CHICAGO OPERATIONS BOSTON FINANCE LONDON

Median (deptno) = 30

Carl Dudley University of Wolverhampton

83

Finding the Median (continued)


Oracle allows the use of ORDER BY in a view This feature allows ROWNUM to be used in a creative fashion SELECT AVG(deptno) Median FROM (SELECT ROWNUM position ,deptno FROM (SELECT deptno FROM dept WHERE deptno IS NOT NULL ORDER BY deptno) ) WHERE position BETWEEN (SELECT COUNT(*)/2 FROM dept WHERE deptno IS NOT NULL) AND (SELECT ROUND((COUNT(*) + 1)/2) FROM dept WHERE deptno IS NOT NULL); The inline view has an ORDER BY which allows the use of ROWNUM AVG is required for sets with an even number of items

Carl Dudley University of Wolverhampton

84

Finding the Median (continued)


DEPTNO -----10 20 30 40

SELECT MEDIAN(deptno) FROM dept;


MEDIAN(DEPTNO) -------------25

DEPTNO -----10 20 30 40 50

SELECT MEDIAN(deptno) FROM dept;


MEDIAN(DEPTNO) -------------30

Carl Dudley University of Wolverhampton

85

Finding the Mode - STATS_MODE

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

Carl Dudley University of Wolverhampton

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)

Carl Dudley University of Wolverhampton

87

SQL Weird and Wonderful Language Carl Dudley


University of Wolverhampton, UK UKOUG SIG Director Oracle ACE Director
carl.dudley@wlv.ac.uk
Carl Dudley University of Wolverhampton 88