+ All Categories
Home > Documents > Dan Stober Intermountain Healthcare - Amazon S3 empno, ename, sal, comm, sal/comm AS comp FROM emp...

Dan Stober Intermountain Healthcare - Amazon S3 empno, ename, sal, comm, sal/comm AS comp FROM emp...

Date post: 02-Apr-2018
Category:
Upload: vuonghanh
View: 219 times
Download: 4 times
Share this document with a friend
69
Dan Stober Intermountain Healthcare *
Transcript

Dan Stober

Intermountain Healthcare

*

*

*Intermountain Healthcare

*Enterprise Data Warehouse (EDW)

*California State University Fresno

*Working in Oracle databases since 2001

*Oracle certified SQL Expert

*Past Presenter at many Oracle conferences

*Oracle Open World, UTOUG, IOUG, OAUG, NYOUG

*

*Learn some intricacies about the SQL works

*Discover a function/keyword that you’ve never seen before

*Gain thorough understanding

*This should help you to…

*Be more productive in your work

*Write code with fewer bugs

*Amaze your co-workers

*Bore your spouse

*

EMPNOEMPNOEMPNOEMPNO ENAMEENAMEENAMEENAME JOBJOBJOBJOB MGRMGRMGRMGR HIREDATEHIREDATEHIREDATEHIREDATE SALSALSALSAL COMM DEPTNOCOMM DEPTNOCOMM DEPTNOCOMM DEPTNO-------------------- ------------------------ ------------------------------------ ---------------- -------------------------------------------- ---------------- ---------------- ------------------------7782 CLARK MANAGER 7839 6/9/1981 2450 107839 KING PRESIDENT 11/17/1981 5000 107934 MILLER CLERK 7782 1/23/1982 1300 10 7369 SMITH CLERK 7902 12/17/1980 800 207566 JONES MANAGER 7839 4/2/1981 2975 207788 SCOTT ANALYST 7566 12/9/1982 3000 207876 ADAMS CLERK 7788 1/12/1983 1100 207902 FORD ANALYST 7566 12/3/1981 3000 20 7499 ALLEN SALESMAN 7698 2/20/1981 1600 300 307521 WARD SALESMAN 7698 2/22/1981 1250 500 307654 MARTIN SALESMAN 7698 9/28/1981 1250 1400 307698 BLAKE MANAGER 7839 5/1/1981 2850 307844 TURNER SALESMAN 7698 9/8/1981 1500 0 307900 JAMES CLERK 7698 12/3/1981 950 30

DEPTNO DEPTNO DEPTNO DEPTNO DNAME LOC DNAME LOC DNAME LOC DNAME LOC ---------- ------------------------- -------------------------

10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON

SELECT * FROM EMP

SELECT * FROM DEPT

*

*NULL issues

*NVL2, NULLIF

*DECODE

*CASE statements

*ROWNUM

*Scoping

*ADD_MONTHS and MONTHS_BETWEEN

*DUMP

*Undocumented Functions

*

*

Empno: 7521

Employee Name: WARD

Salary: 1250

Commission: 500

1250 ÷ 500 = 2.5

Salary is 2.5 times commission

SELECT empno, ename, sal, comm, sal/comm AS comp FROM empWHERE deptno = 30;

Empno: 7844

Employee Name: TURNER

Salary: 1500

Commission: 0

SELECT empno, ename, sal, comm, sal/comm AS comp FROM empWHERE deptno = 30;

*Error at line 1ORA-01476: divisor is equal to zero

*SELECT empno, ename, sal, comm, sal/comm AS comp FROM empWHERE deptno = 30

AND AND AND AND commcommcommcomm <> 0<> 0<> 0<> 0;

SELECT empno, ename, sal, comm, CASE WHEN CASE WHEN CASE WHEN CASE WHEN commcommcommcomm <> 0 THEN <> 0 THEN <> 0 THEN <> 0 THEN salsalsalsal////commcommcommcomm END AS comp END AS comp END AS comp END AS comp FROM empWHERE deptno = 30;

The record for TURNER

has been removed…

…but others records

have been omitted,

too: There are six emps

in DEPTNO 30

All six records

returned

…and no troubles with

division by zero!

SELECT empno, ename, sal, comm, sal/comm AS comp FROM empWHERE deptno = 30

AND AND AND AND commcommcommcomm <> 0<> 0<> 0<> 0;

EMPNO ENAME SAL COMM COMP---------- ---------- ---------- ---------- ----------

7499 ALLEN 1600 300 5.333333337521 WARD 1250 500 2.57654 MARTIN 1250 1400 .892857143

3 rows selected.

SELECT empno, ename, sal, comm, CASE WHEN CASE WHEN CASE WHEN CASE WHEN commcommcommcomm <> 0 THEN <> 0 THEN <> 0 THEN <> 0 THEN salsalsalsal////commcommcommcomm END AS comp END AS comp END AS comp END AS comp FROM empWHERE deptno = 30;

EMPNO ENAME SAL COMM COMP---------- ---------- ---------- ---------- ----------

7499 ALLEN 1600 300 5.333333337521 WARD 1250 500 2.57654 MARTIN 1250 1400 .8928571437698 BLAKE 2850 7844 TURNER 1500 0 7900 JAMES 950

6 rows selected.

*SELECT empno, ename, sal, comm, salsalsalsal / NULLIF ( / NULLIF ( / NULLIF ( / NULLIF ( commcommcommcomm, 0 ) AS , 0 ) AS , 0 ) AS , 0 ) AS comp comp comp comp FROM empWHERE deptno = 30;

NULLIF ( NULLIF ( NULLIF ( NULLIF ( commcommcommcomm, 0 ), 0 ), 0 ), 0 )

If this value… …equals this value… …then return NULL instead

CASE WHEN comm = 0 THEN NULL ELSE comm END

Equivalent to…

NULLIFis one of the most

convenient tools in

the toolkit to avoid

zero_divide errors

SELECT empno, ename, sal, comm, salsalsalsal / NULLIF ( / NULLIF ( / NULLIF ( / NULLIF ( commcommcommcomm, 0 ) AS , 0 ) AS , 0 ) AS , 0 ) AS comp comp comp comp FROM empWHERE deptno = 30;

EMPNO ENAME SAL COMM COMP---------- ---------- ---------- ---------- ----------

7499 ALLEN 1600 300 5.333333337521 WARD 1250 500 2.57654 MARTIN 1250 1400 .8928571437698 BLAKE 2850 7844 TURNER 1500 0 7900 JAMES 950

6 rows selected.

*

In the first solution, the entire division expression is NULLed out…

CASE WHEN comm <> 0 THEN sal/comm END

…but, In the elegant solution, only the zero is NULLed out:

sal / NULL ( comm, 0)

Any addition, subtraction, multiplication, or division

involving a NULL, always results in NULL

*

SELECT empno, ename, sal, comm, salsalsalsal + + + + commcommcommcomm AS AS AS AS ttl_compttl_compttl_compttl_compFROM empWHERE deptno = 30;

sal + comm = ttl_comp

In this case, the ZERO

commission does not

present a problem

However, there is no SUM

for the records with NULL

commissions

NULL in addition, subtraction, multiplication, and division ALWAYS results in NULL

SELECT empno, ename, sal, comm, salsalsalsal + + + + commcommcommcomm AS AS AS AS ttl_compttl_compttl_compttl_compFROM empWHERE deptno = 30;

EMPNO ENAME SAL COMM TTL_COMP---------- ---------- ---------- ---------- ----------

7499 ALLEN 1600 300 19007521 WARD 1250 500 17507654 MARTIN 1250 1400 26507698 BLAKE 2850 7844 TURNER 1500 0 15007900 JAMES 950

6 rows selected.

*SELECT empno, ename, sal, comm, sal + NVL( NVL( NVL( NVL( commcommcommcomm, 0 ), 0 ), 0 ), 0 ) AS ttl_compFROM empWHERE deptno = 30;

NVL ( NVL ( NVL ( NVL ( commcommcommcomm, 0 ), 0 ), 0 ), 0 )

If this value is NULL… …then replace it with this value…

CASE WHEN comm IS NULL THEN 0 ELSE comm END

Equivalent to…

SELECT empno, ename, sal, comm, sal + NVL( NVL( NVL( NVL( commcommcommcomm, 0 ), 0 ), 0 ), 0 ) AS ttl_compFROM empWHERE deptno = 30;

EMPNO ENAME SAL COMM TTL_COMP---------- ---------- ---------- ---------- ----------

7499 ALLEN 1600 300 19007521 WARD 1250 500 17507654 MARTIN 1250 1400 26507698 BLAKE 2850 28507844 TURNER 1500 0 15007900 JAMES 950 950

6 rows selected.

*

*Number + NULL = NULL

*SUM ( numbers and NULL(s) ) returns the SUM

of the NOT NULL values

SELECT COUNT(*), COUNT ( comm ) AS c, SUM ( comm ) AS s, AVG ( comm ) AS a

FROM empWHERE deptno = 30;

COUNT(*) C S A---------- ---------- ---------- ----------

6 4 2200 5501 row selected.

*

SELECT COUNT ( comm )FROM empWHERE deptno = 20;

COUNT(COMM)-----------

01 row selected.

SELECT SUM ( comm )FROM empWHERE deptno = 20;

SUM(COMM)----------

1 row selected.

DECLAREv_sal_sum NUMBER;

BEGINSELECT SUM ( comm )

INTO v_sal_sumFROM empWHERE deptno = 9999;

EXCEPTIONWHEN no_data_found THEN

RAISE invalid_dept;END;

... Program continutes

SELECT SUM ( comm )FROM empWHERE deptno = 9999999999999999;

SUM(COMM)----------

1 row selected.

This exception will NEVER be raised by

this query

*SELECT SUM ( comm )FROM empWHERE deptno = 9999GROUP BY GROUP BY GROUP BY GROUP BY deptnodeptnodeptnodeptno;;;;

no rows selected.

SELECT SUM ( comm )FROM empWHERE deptno = 9999GROUP BY ( );GROUP BY ( );GROUP BY ( );GROUP BY ( );

no rows selected.

GROUP BYusing the single field specified in

the WHERE clauseb

GROUP BYwith empty parentheses

DECLAREv_sal_sum NUMBER;

BEGINSELECT SUM ( comm )

INTO v_sal_sumFROM emp

WHERE deptno = 9999GROUP GROUP GROUP GROUP BY ()BY ()BY ()BY ();

EXCEPTIONWHEN no_data_found THEN

RAISE invalid_dept;END;

... Program continutes

**Count how many employees have a commission

value and how many do not?

SELECT deptno, COUNT(*)FROM empGROUP BY deptno;

DEPTNO COUNT(*)---------- ----------

10 320 530 6

3 rows selected.

SELECT comm, COUNT(*)FROM empGROUP BY comm;

SELECT comm, COUNT(*)FROM empGROUP BY comm;

COMM COUNT(*)---------- ----------

101400 1500 1300 10 1

5 rows selected.

*SELECT NVL2( comm, 'Commission','None') comm

, COUNT(*)FROM empGROUP BY NVL2( comm, 'Commission','None');

NVL2 ( NVL2 ( NVL2 ( NVL2 ( commcommcommcomm, ', ', ', 'Commission','NoneCommission','NoneCommission','NoneCommission','None')')')')

If this value is NOT NULL… …then return this…

CASE WHEN comm IS NOT NULL THEN 'Commission' ELSE 'None' END

Equivalent to…

…If it is NULL, then

return this.

SELECT NVL2( comm, 'Commission','None') comm, COUNT(*)

FROM empGROUP BY NVL2( comm, 'Commission','None');

COMM COUNT(*)-------------------------------- ----------Commission 4None 10

2 rows selected.

*

SELECT NVL2( NULLIF (NULLIF (NULLIF (NULLIF (commcommcommcomm, 0),, 0),, 0),, 0), 'Commission','None') comm, COUNT(*)

FROM empGROUP BY NVL2( NULLIF (comm, 0), 'Commission','None');

Dealing with the record with COMM = 0.

What if it should not be counted with the commissions?

Using NULLIF allows us to NULL out the zero value and

then have it counted with the “None” commission records

SELECT NVL2( NULLIF (NULLIF (NULLIF (NULLIF (commcommcommcomm, 0),, 0),, 0),, 0), 'Commission','None') comm, COUNT(*)

FROM empGROUP BY NVL2( NULLIF (comm, 0), 'Commission','None');

COMM COUNT(*)-------------------------------- ----------Commission 3None 11

2 rows selected.

*

*NVL2 can be used in place of NVL anywhere that NVL is used.

SELECT empno, ename, sal, comm, NVL (comm, 0) n1, NVL2 ( comm, comm, 0) n2NVL2 ( comm, comm, 0) n2NVL2 ( comm, comm, 0) n2NVL2 ( comm, comm, 0) n2, sal + NVL2( comm, comm, 0 ) AS ttl_comp

FROM empWHERE deptno = 30;

EMPNO ENAME SAL COMM N1 N2 TTL_COMP---------- ---------- ---------- ---------- ---------- ---------- ----------

7499 ALLEN 1600 300 300 300 19007521 WARD 1250 500 500 500 17507654 MARTIN 1250 1400 1400 1400 26507698 BLAKE 2850 0 0 28507844 TURNER 1500 0 0 0 15007900 JAMES 950 0 0 950

6 rows selected.

*Old-school function

**Matches values and provides substitutes

*Values and substitutes are in pairs

DECODE ( attendance, 'P','Present','E','Excused','A','Absent')

Test value

or fieldValue and substitute pairs

DECODE ( attendance, 'P','Present','E','Excused','A','Absent','Unknown' )

Default

*

Get a breakdown of the counts of ANALYSTs

versus other employees

SELECT DECODE ( job, 'ANALYST', 'ANALYST', 'OTHERS' ) job , COUNT(*)

FROM empGROUP BY DECODE ( job, 'ANALYST', 'ANALYST', 'OTHERS' ) ;

SELECT DECODE ( job, 'ANALYST', 'ANALYST', 'OTHERS' ) job , COUNT(*)

FROM empGROUP BY DECODE ( job, 'ANALYST', 'ANALYST', 'OTHERS' ) ;

JOB COUNT(*)-------------------------------- ----------OTHERS 12ANALYST 2

2 rows selected.

Trick: DECODE a

value to itself

*Another breakdown...

SELECT DECODE ( job, 'ANALYST', 'ANALYST' , 'CLERK', 'CLERK', 'OTHERS' ) AS jobgroup

, COUNT(*)FROM train.empGROUP BY DECODE ( job, 'ANALYST', 'ANALYST', 'CLERK', 'CLERK', 'OTHERS' );

SELECT DECODE ( job, 'ANALYST', 'ANALYST' , 'CLERK', 'CLERK', 'OTHERS' ) AS jobgroup

, COUNT(*)FROM train.empGROUP BY DECODE ( job, 'ANALYST', 'ANALYST', 'CLERK', 'CLERK', 'OTHERS' );

JOBGROUP COUNT(*)-------------------------------- ----------ANALYST 2CLERK 4OTHERS 8

3 rows selected.

SELECT DECODE ( job, 'ANALYST', jobjobjobjob, 'CLERK', jobjobjobjob, 'OTHERS' ) AS jobgroup

, COUNT(*)FROM train.empGROUP BY DECODE ( job, 'ANALYST', job

, 'CLERK', job, 'OTHERS' );

SELECT DECODE ( job, 'ANALYST', jobjobjobjob, 'CLERK', jobjobjobjob, 'OTHERS' ) AS jobgroup

, COUNT(*)FROM train.empGROUP BY DECODE ( job, 'ANALYST', job

, 'CLERK', job, 'OTHERS' );

JOBGROUP COUNT(*)-------------------------------- ----------ANALYST 2CLERK 4OTHERS 8

3 rows selected.

In these cases, it’s more

common to DECODE

back to the field value

*

Creating a pseudo-group...

*Count the office staff versus the others.

SELECT DECODE ( job, 'ANALYST', 'OFFICEOFFICEOFFICEOFFICE', 'CLERK', 'OFFICEOFFICEOFFICEOFFICE', 'OTHERS' ) AS jobgroup

, COUNT(*)FROM empGROUP BY DECODE ( job, 'ANALYST', 'OFFICE'

, 'CLERK', 'OFFICE', 'OTHERS' );

SELECT DECODE ( job, 'ANALYST', 'OFFICEOFFICEOFFICEOFFICE', 'CLERK', 'OFFICEOFFICEOFFICEOFFICE', 'OTHERS' ) AS jobgroup

, COUNT(*)FROM empGROUP BY DECODE ( job, 'ANALYST', 'OFFICE'

, 'CLERK', 'OFFICE', 'OTHERS' );

JOBGROUP COUNT(*)-------------------------------- ----------OFFICE 6OTHERS 8

2 rows selected.

The ANALYSTs and the

CLERKs have been

grouped together

*

Use it to understand the relationship between

values in two fields

SELECT DECODE ( comm, NULL, 'NULL', 'NOT NULL') comm, DECODE ( mgr, NULL, 'NULL', 'NOT NULL') mgr, COUNT(*)

FROM empGROUP BY DECODE ( comm, NULL, 'NULL', 'NOT NULL') , DECODE ( mgr, NULL, 'NULL', 'NOT NULL')

SELECT DECODE ( comm, NULL, 'NULL', 'NOT NULL') comm, DECODE ( mgr, NULL, 'NULL', 'NOT NULL') mgr, COUNT(*)

FROM empGROUP BY DECODE ( comm, NULL, 'NULL', 'NOT NULL') , DECODE ( mgr, NULL, 'NULL', 'NOT NULL')

COMM MGR COUNT(*)---------------------- ---------------------- ----------NULL NOT NULL 9NOT NULL NOT NULL 4NULL NULL 1

3 rows selected.

In DECODE,

NULL matches

NULL

*

DECODE is very compact when used

in the PARTITION BY for analytic SQL

SELECT ename, job, sal, SUM ( sal ) OVER ( PARTITION BY DECODE(job,'ANALYSTDECODE(job,'ANALYSTDECODE(job,'ANALYSTDECODE(job,'ANALYST',1,'CLERK',1,2',1,'CLERK',1,2',1,'CLERK',1,2',1,'CLERK',1,2) ) ) ) ) AS sum_grp_sal

FROM train.empWHERE deptno <30;

SELECT ename, job, sal, SUM ( sal ) OVER ( PARTITION BY DECODE(job,'ANALYSTDECODE(job,'ANALYSTDECODE(job,'ANALYSTDECODE(job,'ANALYST',1,'CLERK',1,2',1,'CLERK',1,2',1,'CLERK',1,2',1,'CLERK',1,2) ) ) ) ) AS sum_grp_sal

FROM train.empWHERE deptno <30;

ENAME JOB SAL SUM_GRP_SAL---------- --------- ---------- -----------FORD ANALYST 3000 9200SCOTT ANALYST 3000 9200ADAMS CLERK 1100 9200MILLER CLERK 1300 9200SMITH CLERK 800 9200CLARK MANAGER 2450 10425JONES MANAGER 2975 10425KING PRESIDENT 5000 10425

8 rows selected.

*

*

SELECT empno, comm,CASE comm

WHEN 300 THEN 'CCC'WHEN 500 THEN 'L'WHEN NULL THEN 'Empty'ELSE 'Other'

END AS text_fldFROM empWHERE empno IN ( 7499, 7521, 7900 );

SELECT empno, comm,CASE comm

WHEN 300 THEN 'CCC'WHEN 500 THEN 'L'WHEN NULL THEN 'Empty'ELSE 'Other'

END AS text_fldFROM empWHERE empno IN ( 7499, 7521, 7900 );

EMPNO COMM TEXT_FLD---------- ---------- --------

7499 300 CCC 7521 500 L 7900 Other

3 rows selected.

COMM is NULL...

...but, TEXT_FLD

does not contain

the value for NULL

(“Empty”)

*

SELECT empno, comm, CASE WHEN comm = 300 THEN 'CCC'

WHEN comm = 500 THEN 'L'WHEN comm = NULL THEN 'Empty'ELSE 'Other'

END AS text_fldFROM emp

SELECT comm,DECODE ( comm, 300, 'CCC'

, 500, 'L', NULL, 'Empty','Other') AS text_fld

FROM emp

SELECT empno, comm, CASE comm WHEN 300 THEN 'CCC'

WHEN 500 THEN 'L'WHEN NULL THEN 'Empty'

ELSE 'Other'END AS text_fld

FROM emp

This Searched CASE statement

is equivalent to the Matched

CASE above

This is why the NULL doesn’t

match

comm = NULL

DECODE behaves differently. It

does match on NULL

(as we’ve seen already)

*

*

SELECT ename, salFROM empWHERE ROWNUM <= 2ORDER BY sal DESC;

ENAME SAL---------- ----------ALLEN 1600SMITH 800

2 rows selected.

Objective:

SELECT the two highest salaries...

SELECT ename, salFROM empWHERE ROWNUM <= 2ORDER BY sal DESC;

Use ORDER BY to sort

the records and then

ROWNUM to get the

first two.

Is this right?

No. In a query,

ROWNUM gets assigned

to the records before

the ORDER BY

KING 5000

FORD 3000

SCOTT 3000

JONES 2975

BLAKE 2850

CLARK 2450

ALLEN 1600

TURNER 1500

WARD 1250

MILLER 1300

MARTIN 1250

ADAMS 1100

JAMES 950

SMITH 800

*SELECT ROWNUM, ename, mgr, sal

FROM emp;

ROWNUM ENAME SAL---------- ---------- ----------

1 SMITH 8002 ALLEN 16003 WARD 12504 JONES 29755 MARTIN 12506 BLAKE 28507 CLARK 24508 SCOTT 30009 KING 500010 TURNER 150011 ADAMS 110012 SALES 95013 FORD 300014 MILLER 1300

14 rows selected.

SELECT ROWNUM, empno, ename, mgr

FROM empORDER BY ORDER BY ORDER BY ORDER BY salsalsalsal DESCDESCDESCDESC;

ROWNUM ENAME SAL---------- ---------- ----------

9 KING 500013 FORD 30008 SCOTT 30004 JONES 29756 BLAKE 28507 CLARK 24502 ALLEN 160010 TURNER 150014 MILLER 13003 WARD 12505 MARTIN 125011 ADAMS 110012 SALES 9501 SMITH 800

14 rows selected.

Records are selected in database order.

ROWNUM is assigned based on that.

*SELECT * FROM ( SELECT ename, sal

FROM empORDER BY sal DESC )

WHERE ROWNUM <= 2;

SELECT * FROM ( SELECT ename, sal

FROM empORDER BY sal DESC )

WHERE ROWNUM <= 2;

ENAME SAL---------- ----------KING 5000SCOTT 3000

2 rows selected.

Using a subquery, we can sort

the records before the

ROWNUM is applied

SELECT ROWNUM, ename, salFROM ( SELECT ename, sal

FROM empORDER BY sal DESC )

WHERE ROWNUM <= 2;

ROWNUM ENAME SAL---------- ---------- ----------

1 KING 50002 SCOTT 3000

2 rows selected.

*SELECT * FROM ( SELECT ROWNUM, ename, sal

FROM empORDER BY sal DESC ) sub

WHERE ROWNUM <= 2;

ROWNUM ENAME SAL---------- ---------- ----------

9 KING 50008 SCOTT 3000

2 rows selected.

SELECT ROWNUM, sub.* FROM ( SELECT ROWNUM, ename, sal

FROM empORDER BY sal DESC ) sub

WHERE ROWNUM <= 2;

ROWNUM ROWNUM_1 ENAME SAL---------- ---------- ---------- ----------

1 9 KING 50002 8 SCOTT 3000

2 rows selected.

The WHERE clause selected

ROWNUM < 2,

but values in the query

are 8 and 9.

*

SELECT ROWNUM , empno, enameFROM train.empWHERE ROWNUM = 2 ;

ROWNUM 2 does not exist until after

ROWNUM 1 is assigned

SELECT ROWNUM , empno, enameFROM train.empWHERE ROWNUM = 2 ;

no rows selected.

You cannot select ROWNUM 2 unless

ROWNUM 1 is also selected

*

*ROWNUM is a pseudocolumn

*Not found in the data

*Assigned as the records are selected

*At the end of the WHERE clause

*This means that ROWNUM can be used in the WHERE clause

*

*SELECT ename, jobFROM empWHERE job IN ( SELECT job FROM dept);

SELECT ename, jobFROM empWHERE job IN ( SELECT job FROM dept);

ENAME JOB ---------- ---------ADAMS CLERK ALLEN SALESMAN BLAKE MANAGER CLARK MANAGER FORD ANALYST JAMES CLERK JONES MANAGER KING PRESIDENTMARTIN SALESMAN MILLER CLERK SCOTT ANALYST SMITH CLERK TURNER SALESMAN WARD SALESMAN

14 rows selected.

Why every record?

There is no JOB field in

the DEPT table

The query is equivalent

to this one:

SELECT ename, jobFROM empWHERE job = jobWHERE job = jobWHERE job = jobWHERE job = job

SELECT ename, jobFROM emp eWHERE e.job IN ( SELECT d.job FROM dept d);

SELECT ename, jobFROM emp eWHERE e.job IN ( SELECT d.job FROM dept d);*Error at line 3Error at line 3Error at line 3Error at line 3ORAORAORAORA----00904: "D"."JOB": invalid identifier00904: "D"."JOB": invalid identifier00904: "D"."JOB": invalid identifier00904: "D"."JOB": invalid identifier

*

*

*ADD_MONTHS: Returns a DATE some number of months

away (forward or back) from a date supplied

*MONTHS_BETWEEN: Returns the number of months

between two dates.

*There are special considerations due to the fact that not

all months are the same length

SELECT MONTHS_BETWEEN ( DATE '2015-01-01', DATE '2015-03-01')

FROM DUAL;

SELECT MONTHS_BETWEEN ( DATE '2015-03-01', DATE '2015-01-01')

FROM DUAL;

SELECT MONTHS_BETWEEN ( DATE '2015-01-01', DATE '2015-03-01')

FROM DUAL;

MONTHS_BETWEEN(DATE'2015-01-01',DATE'2015-03-01')-------------------------------------------------

-2

1 row selected.

SELECT MONTHS_BETWEEN ( DATE '2015-03-01', DATE '2015-01-01')

FROM DUAL;

MONTHS_BETWEEN(DATE'2015-01-01',DATE'2015-03-01')-------------------------------------------------

2

1 row selected.

Oddity?

Annoyance!

*SELECT ADD_MONTHS

( DATE '2015-01-01', 2 )FROM DUAL;

SELECT ADD_MONTHS( DATE '2015-01-01', 2.5 )

FROM DUAL;

SELECT ADD_MONTHS( DATE '2015-01-01', 2 )

FROM DUAL;

ADD_MONTHS(DATE'2015-01-01',2)------------------------------01-MAR-15

1 row selected.

SELECT ADD_MONTHS( DATE '2015-01-01', 2.5 )

FROM DUAL;

ADD_MONTHS(DATE'2015-01-01',2.5)--------------------------------01-MAR-15

1 row selected.

ADD_MONTHS adds whole

months only.

If you provide a fractional

month, the value is truncated

before the calculation

*

SELECT ADD_MONTHS( ADD_MONTHS (DATE '2015-01-27', 1 ), -1)

FROM DUAL;

SELECT ADD_MONTHS( ADD_MONTHS (DATE '2015-01-28', 1 ), -1)

FROM DUAL;

SELECT ADD_MONTHS( ADD_MONTHS (DATE '2015-01-27', 1 ), -1)

FROM DUAL;

ADD_MONTHS(ADD_MONTHS(DATE'2015-01-27',1),-1)---------------------------------------------27-JAN-15

1 row selected.

SELECT ADD_MONTHS( ADD_MONTHS (DATE '2015-01-28', 1 ), -1)

FROM DUAL;

ADD_MONTHS(ADD_MONTHS(DATE'2015-01-28',1),-1)---------------------------------------------31-JAN-15

1 row selected.ADD_MONTHS, when called

from the last day of the

month,

always returns the last day

of the target month

*SELECT MONTHS_BETWEEN

( DATE '2015-03-31', DATE '2015-02-28' )FROM DUAL;

MONTHS_BETWEEN(DATE'2015-03-31',DATE'2015-02-28')-------------------------------------------------

11 row selected.

SELECT MONTHS_BETWEEN( DATE '2015-03-29', DATE '2015-02-28' )

FROM DUAL;

MONTHS_BETWEEN(DATE'2015-03-29',DATE'2015-02-28')-------------------------------------------------

1.032258061 row selected.

Feb 28 to Mar 31 31 days

Feb 28 to Mar 29 29 days

SELECT MONTHS_BETWEEN( DATE '2015-03-28', DATE '2015-02-28' )

FROM DUAL;

MONTHS_BETWEEN(DATE'2015-03-28',DATE'2015-02-28')-------------------------------------------------

11 row selected.

Feb 28 to Mar 28 28 days

**ADD_MONTHS

* If starting point is the last day of the month…

*…then ADD_MONTHS always returns the last day of the target month

*Otherwise, ADD_MONTHS returns the day with the same number in the target month

*MONTHS_BETWEEN

* If starting point (second param) is the last day of the month…

*…then it always results in an integer number of months to the last day of a month

*Otherwise, the decimal portion is 1/31 times the number of days in the remainder

Feb 28 to Mar 31 31 days

Feb 28 to Mar 28 28 days

BOTHare one month apart

*SELECT MONTHS_BETWEEN

( DATE '2015-03-02', DATE '2015-03-01' ) AS mar, MONTHS_BETWEEN( DATE '2015-04-02', DATE '2015-04-01' ) AS apr, MONTHS_BETWEEN( DATE '2015-02-02', DATE '2015-02-01' ) AS feb15, MONTHS_BETWEEN( DATE '2016-02-02', DATE '2016-02-01' ) AS feb16

, 1/ 31 AS math_calcFROM DUAL;

SELECT MONTHS_BETWEEN( DATE '2015-03-02', DATE '2015-03-01' ) AS mar, MONTHS_BETWEEN( DATE '2015-04-02', DATE '2015-04-01' ) AS apr, MONTHS_BETWEEN( DATE '2015-02-02', DATE '2015-02-01' ) AS feb15, MONTHS_BETWEEN( DATE '2016-02-02', DATE '2016-02-01' ) AS feb16

, 1/ 31 AS math_calcFROM DUAL;

MAR APR FEB15 FEB16 MATH_CALC---------- ---------- ---------- ---------- ----------.032258065 .032258065 .032258065 .032258065 .032258065

1 row selected.

Regardless of the actual

length of the month,

MONTHS_BETWEEN always

returns 1/31

*

12/31/2014 01/28/2015 0.903225806 28 / 31

12/31/2014 01/29/2015 0.935483871 29 / 31

12/31/2014 01/30/2015 0.967741935 30 / 31

12/31/2014 01/31/2015 1.000000000 31 / 31

03/31/2015 04/27/2015 0.870967742 27 / 31

03/31/2015 04/28/2015 0.903225806 28 / 31

03/31/2015 04/29/2015 0.935483871 29 / 31

03/31/2015 04/30/2015 1.000000000 31 / 31

2/31

difference

for one day

*

Calculating AGE!

age = TRUNC ( SYSDATE – birthdate ) / 365.25 )

As of date Age days Divided by 365.25 TRUNC

03/01/2013 365 0.99931553730217 0

03/01/2014 730 1.99863107460643 1

03/01/2015 1095 2.99794661190965 2

03/01/2016 1461 4.00000000000000 4

365 / 365.25 < 1

For someone born on March 1, 2012...

*

Calculating AGE!

age = TRUNC ( MONTHS_BETWEEN ( SYSDATE, birthdate ) / 12)

As of date MONTHS_BETWEEN Divided by 12 TRUNC

03/01/2013 12 1 1

03/01/2014 24 2 2

03/01/2015 36 3 3

03/01/2016 48 4 4

*The only scenario where this method will return the incorrect age (possibly) is people born on February 29.

* In years without a Leap Year, it reports birthday on Feb 28

* 1 in 1461 people ( 0.068%) …in 3 out of 4 years

*Fractional ages could suffer the same oddities seen previously

* But whole ages always land in the same month as the start date

For someone born on March 1, 2012...

*One of my favorite functions

**DUMP is a data checking function

*Returns the contents of a field, character by character

* Including non-printable (invisible) characters

*Best used when troubleshooting

SELECT ename, DUMP ( ename )FROM empWHERE deptno = 10;

SELECT ename, DUMP ( ename )FROM empWHERE deptno = 10;

ENAME DUMP(ENAME) ---------- --------------------------------------------------KING Typ=1 Len=4: 75,73,78,71 CLARK Typ=1 Len=5: 67,76,65,82,75 MILLER Typ=1 Len=6: 77,73,76,76,69,82

3 rows selected.

Datatype Length ASCII value of each character

*

Code Datatype

1 VARCHAR, NVARCHAR2

2 NUMBER, FLOAT

8 DATE

12 LONG

96 CHAR, NCHAR

*

SELECT ename, DUMP ( ename,17 )FROM empWHERE deptno = 10;

SELECT ename, DUMP ( ename,17 )FROM empWHERE deptno = 10;

ENAME DUMP(ENAME,17)

---------------------------------------KING Typ=1 Len=4: K,I,N,GCLARK Typ=1 Len=5: C,L,A,R,KMILLER Typ=1 Len=6: M,I,L,L,E,R

3 rows selected.

Now, each character is

represented as itself

But…watch what happens with

non-printable characters!

*

SELECT business_unit, account, deptid, posted_total_amt_txtFROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

SELECT business_unit, account, deptid, posted_total_amt_txtFROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

BUSINESS_UNIT ACCOUNT DEPTID POSTED_TOTAL_AMT_TXT ------------- ---------- ---------- ------------------------------4321 123456 10011 216.57

4321 123456 11503 1089.66

4321 123456 14010 4555.11

3 rows selected. SELECT business_unit, account, deptid, TO_NUMBERTO_NUMBERTO_NUMBERTO_NUMBER ( posted_total_amt_txt )FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

SELECT business_unit, account, deptid, TO_NUMBERTO_NUMBERTO_NUMBERTO_NUMBER ( posted_total_amt_txt )FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

Error at line 4ORA-01722: invalid number

*SELECT business_unit, account, deptid, posted_total_amt_txt, DUMP DUMP DUMP DUMP ( posted_total_amt_txt )FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

SELECT business_unit, account, deptid, posted_total_amt_txt, DUMPDUMPDUMPDUMP ( posted_total_amt_txt )FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

BUSINESS_UNIT ACCOUNT DEPTID POSTED_T DUMP(POSTED_TOTAL_AMT_TXT) ------------- ------- ------- -------- ----------- ----------------------------------4321 123456 10011 216.57 Typ=1 Len=8: 50,49,54,46,53,55,32,134321 123456 11503 1089.66 Typ=1 Len=9: 49,48,56,57,46,54,54,32,134321 123456 14010 4555.11 Typ=1 Len=9: 52,53,53,53,46,49,49,32,13

3 rows selected.

SELECT business_unit, account, deptid, posted_total_amt_txt, DUMPDUMPDUMPDUMP ( posted_total_amt_txt, 17171717 )FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

SELECT business_unit, account, deptid, posted_total_amt_txt, DUMPDUMPDUMPDUMP ( posted_total_amt_txt, 17171717 )FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

BUSINESS_UNIT ACCOUNT DEPTID POSTED_T DUMP(POSTED_TOTAL_AMT_TXT) ------------- ------- ------- -------- ----------- ---------------------------------4321 123456 10011 216.57 Typ=1 Len=8: Typ=1 Len=8: 2,1,6,.,5,7, ,^M 4321 123456 11503 1089.66 Typ=1 Len=9: Typ=1 Len=9: 1,0,8,9,.,6,6, ,^M4321 123456 14010 4555.11 Typ=1 Len=9: Typ=1 Len=9: 4,5,5,5,.,1,1, ,^M

3 rows selected.

Here is the

offending character

And here is the ASCII

number

*

SELECT business_unit, account, deptid, TO_NUMBER ( REPLACEREPLACEREPLACEREPLACE ( posted_total_amt_txt, CHR(13)CHR(13)CHR(13)CHR(13) ))FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

SELECT business_unit, account, deptid, TO_NUMBER ( REPLACEREPLACEREPLACEREPLACE ( posted_total_amt_txt, CHR(13)CHR(13)CHR(13)CHR(13) ))FROM erp_ledger_insertWHERE deptid IN ( 10011, 11503, 14010);

BUSINESS_UNIT ACCOUNT DEPTID TO_NUMBER(REPLACE(POSTED_TOTAL_AMT_TXT,CHR(13)))------------- ---------- ---------- ------------------------------------------------4321 123456 10011 216.574321 123456 11503 1089.664321 123456 14010 4555.11

3 rows selected.

The character 13 is REPLACEd out

of the string

*Another example…

*

SELECT SUBSTR ( company, 1, INSTR ( company, ' ')) AS ticker, djia.* FROM djia;

TICKER COMPANY PRICE-------------------- ----------------------------------------- ----------MMM 3M MMM 3M Co 137.72AXP American AXP American Express Co 87.77T AT&T T AT&T Inc 35.43BA Boeing BA Boeing Co 128.33CAT Caterpillar CAT Caterpillar Inc 105.18CVX Chevron CVX Chevron Corp 126.57CSCO Cisco CSCO Cisco Systems Inc 23.18DD E DD E I du Pont de Nemours and Co 67.01XOM Exxon XOM Exxon Mobil Corp 101.63GE General GE General Electric Co 26.69GS Goldman GS Goldman Sachs Group Inc 157.92HD Home HD Home Depot Inc 79.57INTC Intel INTC Intel Corp 26.5IBM International IBM International Business Machines Co... 195.47JNJ Johnson JNJ Johnson & Johnson 101.2JPM JPMorgan JPM JPMorgan Chase and Co 56.02MCD McDonald's MCD McDonald's Corp 101.54MRK Merck MRK Merck & Co Inc 58.42MSFT Microsoft MSFT Microsoft Corp 40.6NKE Nike NKE Nike Inc 72.55PFE Pfizer PFE Pfizer Inc 31.65PG Procter PG Procter & Gamble Co 82.55KO The KO The Coca-Cola Co 40.53

SUBSTR ( company, 1, INSTR ( company, ' '))

Full DJIA query in slide note

*

SELECT INSTR ( company, ' ') AS space_loc, djia.*FROM djia;

SPACE_LOC COMPANY PRICE---------- ----------------------------------------- ----------

7 MMM 3M Co 137.7213 AXP American Express Co 87.777 T AT&T Inc 35.4310 BA Boeing Co 128.3316 CAT Caterpillar Inc 105.1812 CVX Chevron Corp 126.5711 CSCO Cisco Systems Inc 23.185 DD E I du Pont de Nemours and Co 67.0110 XOM Exxon Mobil Corp 101.6311 GE General Electric Co 26.6911 GS Goldman Sachs Group Inc 157.928 HD Home Depot Inc 79.5711 INTC Intel Corp 26.518 IBM International Business Machines Co... 195.4712 JNJ Johnson & Johnson 101.213 JPM JPMorgan Chase and Co 56.0215 MCD McDonald's Corp 101.5410 MRK Merck & Co Inc 58.4215 MSFT Microsoft Corp 40.69 NKE Nike Inc 72.5511 PFE Pfizer Inc 31.6511 PG Procter & Gamble Co 82.557 KO The Coca-Cola Co 40.53

INSTR ( company, ' ')

So….

What is

going on?

SELECT company, DUMP ( company)

FROM djia;

*

SELECT company, DUMP ( company)

FROM djia;

COMPANY DUMP(COMPANY)----------------------------------------- --------------------------------------------------------------------------------------MMM 3M Co Typ=1 Len=9: 77,77,77,160160160160,51,77,32323232,67,111AXP American Express Co Typ=1 Len=23: 65,88,80,160160160160,65,109,101,114,105,99,97,110,T AT&T Inc Typ=1 Len=10: 84,160160160160,65,84,38,84,32323232,73,110,99BA Boeing Co Typ=1 Len=12: 66,65,160160160160,66,111,101,105,110,103,32323232,67,111CAT Caterpillar Inc Typ=1 Len=19: 67,65,84,160160160160,67,97,116,101,114,112,105,108,108,97,114,CVX Chevron Corp Typ=1 Len=16: 67,86,88,160160160160,67,104,101,118,114,111,110,CSCO Cisco Systems Inc Typ=1 Len=22: 67,83,67,79,160160160160,67,105,115,99,111,32323232,83,121,115,116,101,109,115,DD E I du Pont de Nemours and Co Typ=1 Len=32: 68,68,160160160160,69,32323232,73,32323232,100,117,32323232,80,111,110,116,XOM Exxon Mobil Corp Typ=1 Len=20: 88,79,77,160160160160,69,120,120,111,110,32323232,77,111,98,105,108,GE General Electric Co Typ=1 Len=22: 71,69,160160160160,71,101,110,101,114,97,108,32323232GS Goldman Sachs Group Inc Typ=1 Len=26: 71,83,160160160160,71,111,108,100,109,97,110,32323232HD Home Depot Inc Typ=1 Len=17: 72,68,160160160160,72,111,109,101,32323232,68,101,112,111,116,INTC Intel Corp Typ=1 Len=15: 73,78,84,67,160160160160,73,110,116,101,108,32323232IBM International Business Machines Co... Typ=1 Len=41: 73,66,77,160160160160,73,110,116,101,114,110,97,116,105,111,110,97,108,32,66,117,115JNJ Johnson & Johnson Typ=1 Len=21: 74,78,74,160160160160,74,111,104,110,115,111,110,JPM JPMorgan Chase and Co Typ=1 Len=25: 74,80,77,160160160160,74,80,77,111,114,103,97,110,MCD McDonald's Corp Typ=1 Len=19: 77,67,68,160160160160,77,99,68,111,110,97,108,100,39,115,MRK Merck & Co Inc Typ=1 Len=18: 77,82,75,160160160160,77,101,114,99,107,32323232,38,MSFT Microsoft Corp Typ=1 Len=19: 77,83,70,84,160160160160,77,105,99,114,111,115,111,102,116,NKE Nike Inc Typ=1 Len=12: 78,75,69,160160160160,78,105,107,101,32323232,73,110,99PFE Pfizer Inc Typ=1 Len=14: 80,70,69,160160160160,80,102,105,122,101,114,32,73,110,99PG Procter & Gamble Co Typ=1 Len=22: 80,71,160160160160,80,114,111,99,116,101,114,32,38,32,71,97,109,98,108,101,32,67,111KO The Coca-Cola Co Typ=1 Len=19: 75,79,160160160160,84,104,101,32323232,67,111,99,97,45,67,111,108,97,32,67,111TRV Travelers Companies Inc Typ=1 Len=27: 84,82,86,160160160160,84,114,97,118,101,108,101,114,115,UTX United Technologies Corp Typ=1 Len=28: 85,84,88,160160160160,85,110,105,116,101,100,32323232

DUMP ( company )

SELECT company, DUMP ( company, 17)

FROM djia;

SELECT company, DUMP ( company, 17)

FROM djia;

COMPANY DUMP(COMPANY,17)----------------------------------------- --------------------------------------------------------------------------------------AXP American Express Co Typ=1 Len=23: A,X,P, ,A,m,e,r,i,c,a,n, ,E,x,p,r,e,s,s, ,C,o BA Boeing Co Typ=1 Len=12: B,A, ,B,o,e,i,n,g, ,C,o CAT Caterpillar Inc Typ=1 Len=19: C,A,T, ,C,a,t,e,r,p,i,l,l,a,r, ,I,n,c CSCO Cisco Systems Inc Typ=1 Len=22: C,S,C,O, ,C,i,s,c,o, ,S,y,s,t,e,m,s, ,I,n,c CVX Chevron Corp Typ=1 Len=16: C,V,X, ,C,h,e,v,r,o,n, ,C,o,r,p DD E I du Pont de Nemours and Co Typ=1 Len=32: D,D, ,E, ,I, ,d,u, ,P,o,n,t, ,d,e, ,N,e,m,o,u,r,s, ,a,n,d, ,C,o DIS Walt Disney Co Typ=1 Len=18: D,I,S, ,W,a,l,t, ,D,i,s,n,e,y, ,C,o GE General Electric Co Typ=1 Len=22: G,E, ,G,e,n,e,r,a,l, ,E,l,e,c,t,r,i,c, ,C,o GS Goldman Sachs Group Inc Typ=1 Len=26: G,S, ,G,o,l,d,m,a,n, ,S,a,c,h,s, ,G,r,o,u,p, ,I,n,c HD Home Depot Inc Typ=1 Len=17: H,D, ,H,o,m,e, ,D,e,p,o,t, ,I,n,c IBM International Business Machines Co... Typ=1 Len=41: I,B,M, ,I,n,t,e,r,n,a,t,i,o,n,a,l, ,B,u,s,i,n,e,s,s, ,M,a,c,h,i,n,e,sINTC Intel Corp Typ=1 Len=15: I,N,T,C, ,I,n,t,e,l, ,C,o,r,p JNJ Johnson & Johnson Typ=1 Len=21: J,N,J, ,J,o,h,n,s,o,n, ,&, ,J,o,h,n,s,o,n JPM JPMorgan Chase and Co Typ=1 Len=25: J,P,M, ,J,P,M,o,r,g,a,n, ,C,h,a,s,e, ,a,n,d, ,C,o KO The Coca-Cola Co Typ=1 Len=19: K,O, ,T,h,e, ,C,o,c,a,-,C,o,l,a, ,C,o MCD McDonald's Corp Typ=1 Len=19: M,C,D, ,M,c,D,o,n,a,l,d,',s, ,C,o,r,p MMM 3M Co Typ=1 Len=9: M,M,M, ,3,M, ,C,o MRK Merck & Co Inc Typ=1 Len=18: M,R,K, ,M,e,r,c,k, ,&, ,C,o, ,I,n,c MSFT Microsoft Corp Typ=1 Len=19: M,S,F,T, ,M,i,c,r,o,s,o,f,t, ,C,o,r,p NKE Nike Inc Typ=1 Len=12: N,K,E, ,N,i,k,e, ,I,n,c PFE Pfizer Inc Typ=1 Len=14: P,F,E, ,P,f,i,z,e,r, ,I,n,c PG Procter & Gamble Co Typ=1 Len=22: P,G, ,P,r,o,c,t,e,r, ,&, ,G,a,m,b,l,e, ,C,o T AT&T Inc Typ=1 Len=10: T, ,A,T,&,T, ,I,n,cTRV Travelers Companies Inc Typ=1 Len=27: T,R,V, ,T,r,a,v,e,l,e,r,s, ,C,o,m,p,a,n,i,e,s, ,I,n,c UNH UnitedHealth Group Inc Typ=1 Len=26: U,N,H, ,U,n,i,t,e,d,H,e,a,l,t,h, ,G,r,o,u,p, ,I,n,c

DUMP ( company, 17 )

*

SELECTCASE

WHEN company LIKE 'VZ%'OR company LIKE 'KO%' THEN ASCII ( SUBSTR ( company, 3, 1))

WHEN company LIKE 'MMM%'OR company LIKE 'AXP%' THEN ASCII ( SUBSTR ( company, 4, 1))

WHEN company LIKE 'CSCO%'OR company LIKE 'INTC%' THEN ASCII ( SUBSTR ( company, 5, 1))

END AS mystery_char, company

FROM djiaWHERE company LIKE 'VZ%'

OR company LIKE 'KO%'OR company LIKE 'MMM%'OR company LIKE 'AXP%'OR company LIKE 'CSCO%'OR company LIKE 'INTC%‘;

SELECTCASE

WHEN company LIKE 'VZ%'OR company LIKE 'KO%' THEN ASCII ( SUBSTR ( company, 3, 1))

WHEN company LIKE 'MMM%'OR company LIKE 'AXP%' THEN ASCII ( SUBSTR ( company, 4, 1))

WHEN company LIKE 'CSCO%'OR company LIKE 'INTC%' THEN ASCII ( SUBSTR ( company, 5, 1))

END AS mystery_char, company

FROM djiaWHERE company LIKE 'VZ%'

OR company LIKE 'KO%'OR company LIKE 'MMM%'OR company LIKE 'AXP%'OR company LIKE 'CSCO%'OR company LIKE 'INTC%';

MYSTERY_CHAR COMPANY------------ -----------------------------

160 MMM 3M Co160 AXP American Express Co160 CSCO Cisco Systems Inc160 INTC Intel Corp160 KO The Coca-Cola Co160 VZ Verizon Communications Inc

6 rows selected.

Using the SUBSTR

function to isolate

just one character

from the string

*DUMPDUMPDUMPDUMP: Returns the ASCII value of every character in the

string

*ASCIIASCIIASCIIASCII: Returns the ASCII value of just one character

*

*

*

*Returns the characters from a string in reverse order

*Cannot be called on numbers

SELECT ename, REVERSEREVERSEREVERSEREVERSE ( ename ) revFROM empWHERE deptno = 30;

ENAME REV ---------- ----------ALLEN NELLA BLAKE EKALB JAMES SEMAJ MARTIN NITRAM TURNER RENRUT WARD DRAW

6 rows selected.

SELECT empno, REVERSEREVERSEREVERSEREVERSE ( empno ) revFROM empWHERE deptno = 30;

*Error at line 2ORA-00932: inconsistent datatypes: expected CHAR got NUMBER

*

*Compares characters from two strings

*If the characters in the same position from the

two strings match, it returns the character

*If they do not match, function returns “B” in

that character’s place

*Usefulness? Zero…SELECT ename, job, merge$actions ( ename, job ) FROM empWHERE comm IS NOT NULL;

ENAME JOB MERGE$ACTIONS(ENAME,JOB)---------- --------- ------------------------ALLEN SALESMAN BBLEB MARTIN SALESMAN BABBBB TURNER SALESMAN BBBBBB WARD SALESMAN BABB

4 rows selected.

**Returns:

*0 if two values are identical

*1 if they are not

*Overloads for numbers, characters, and dates

WITH dta AS (SELECT ename, job

, LEAD ( job ) OVER ( ORDER BY empno ) job1FROM empWHERE deptno = 30)

SELECT ename, job, job1, SYS_OP_DISTINCT ( job, job1) fFROM dta ;

ENAME JOB JOB1 F---------- --------- --------- ----------ALLEN SALESMAN SALESMAN 0BLAKE MANAGER SALESMAN 1JAMES CLERK 1MARTIN SALESMAN MANAGER 1TURNER SALESMAN CLERK 1WARD SALESMAN SALESMAN 0

6 rows selected.

*

*Don’t try this one at home!

*I ran it in TOAD, too.

* It caused system resource issues

* I had to shut down TOAD and reopen it

SELECT DENSE_RANKM( ename ) OVER (ORDER BY deptno, sal) FROM emp;

ERROR at line 1:ORA-03113: end-of-file on communication channel

*

*NULL issues

*NVL2, NULLIF

*DECODE

*CASE statements

*ROWNUM

*Scoping

*ADD_MONTHS and MONTHS_BETWEEN

*DUMP

*Undocumented Functions

*

Dan Stober

[email protected]

Twitter @dstober


Recommended