SlideShare a Scribd company logo
1
Connor McDonald
bit.ly/techguysong
The power of SQL analytics
Connor McDonald
Database Advocate
Copyright © 2019 Oracle and/or its affiliates.
3 3
4 4
5
Me
youtube bit.ly/youtube-connor
blog connor-mcdonald.com
twitter @connor_mc_d
400+ posts mainly on database & development
250 technical videos, new uploads every week
rants and raves on tech and the world :-)
6
etc...
facebook bit.ly/facebook-connor
linkedin bit.ly/linkedin-connor
instagram bit.ly/instagram-connor
slideshare bit.ly/slideshare-connor
7
the beauty of analytics
8
simple syntax
9
<function> ( <arg>,<arg>,… )
OVER (
<partition clause>
<sorting clause>
<windowing clause>
)
10
<function> ( <arg>,<arg>,… )
OVER | KEEP (
<partition clause>
<sorting clause>
<windowing clause>
)
11
that’s it !
12
quick example #1
13
our sample data
14
employees by salary
SQL> select empno, ename, job, hiredate, sal
2 from emp
3 order by sal;
EMPNO ENAME JOB HIREDATE SAL
---------- ---------- --------- --------- ----------
7369 SMITH CLERK 17-DEC-80 800
7900 JAMES CLERK 03-DEC-81 950
7876 ADAMS CLERK 12-JAN-83 1100
7521 WARD SALESMAN 22-FEB-81 1250
7654 MARTIN SALESMAN 28-SEP-81 1250
7934 MILLER CLERK 23-JAN-82 1300
7844 TURNER SALESMAN 08-SEP-81 1500
7499 ALLEN SALESMAN 20-FEB-81 1600
7782 CLARK MANAGER 09-JUN-81 2450
7698 BLAKE MANAGER 01-MAY-81 2850
7566 JONES MANAGER 02-APR-81 2975
7902 FORD ANALYST 03-DEC-81 3000
7788 SCOTT ANALYST 09-DEC-82 3000
7839 KING PRESIDENT 17-NOV-81 5000
16
"Show me the hiring sequence"
EMPNO ENAME JOB HIREDATE SAL HIRE_SEQ
---------- ---------- --------- --------- ---------- ----------
7369 SMITH CLERK 17-DEC-80 800 1
7900 JAMES CLERK 03-DEC-81 950 10
7876 ADAMS CLERK 12-JAN-83 1100 14
7521 WARD SALESMAN 22-FEB-81 1250 3
7654 MARTIN SALESMAN 28-SEP-81 1250 8
7934 MILLER CLERK 23-JAN-82 1300 12
7844 TURNER SALESMAN 08-SEP-81 1500 7
7499 ALLEN SALESMAN 20-FEB-81 1600 2
7782 CLARK MANAGER 09-JUN-81 2450 6
7698 BLAKE MANAGER 01-MAY-81 2850 5
7566 JONES MANAGER 02-APR-81 2975 4
7902 FORD ANALYST 03-DEC-81 3000 10
7788 SCOTT ANALYST 09-DEC-82 3000 13
7839 KING PRESIDENT 17-NOV-81 5000 9
SMITH was hired "first"
ADAMS was hired “last"
without analytics
SQL> select e.empno, e.ename, e.job,
2 e.hiredate, e.sal, x.seq
3 from emp e,
4 ( select e2.empno, count(*) seq
5 from emp e1, emp e2
6 where e1.hiredate <= e2.hiredate
7 group by e2.empno
8 ) x
9 where e.empno = x.empno
10 order by sal;
------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |
------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 1390 |
| 1 | SORT GROUP BY | | 10 | 1390 |
|* 2 | HASH JOIN | | 10 | 1390 |
| 3 | MERGE JOIN | | 10 | 310 |
| 4 | SORT JOIN | | 14 | 126 |
| 5 | TABLE ACCESS FULL| EMP | 14 | 126 |
|* 6 | SORT JOIN | | 14 | 308 |
| 7 | TABLE ACCESS FULL| EMP | 14 | 308 |
| 8 | TABLE ACCESS FULL | EMP | 14 | 1512 |
------------------------------------------------------
SQL> select empno, ename, job, hiredate, sal,
2 rank() OVER (order by hiredate) as hire_seq
3 from emp
4 order by sal;
EMPNO ENAME JOB HIREDATE SAL HIRE_SEQ
---------- ---------- --------- --------- ---------- ----------
7369 SMITH CLERK 17-DEC-80 800 1
7900 JAMES CLERK 03-DEC-81 950 10
7876 ADAMS CLERK 12-JAN-83 1100 14
7521 WARD SALESMAN 22-FEB-81 1250 3
7654 MARTIN SALESMAN 28-SEP-81 1250 8
7934 MILLER CLERK 23-JAN-82 1300 12
7844 TURNER SALESMAN 08-SEP-81 1500 7
7499 ALLEN SALESMAN 20-FEB-81 1600 2
7782 CLARK MANAGER 09-JUN-81 2450 6
7698 BLAKE MANAGER 01-MAY-81 2850 5
7566 JONES MANAGER 02-APR-81 2975 4
7902 FORD ANALYST 03-DEC-81 3000 10
7788 SCOTT ANALYST 09-DEC-82 3000 13
7839 KING PRESIDENT 17-NOV-81 5000 9
rank() OVER (
order by hire_date) as hire_seq
function
sorting clause
functions
for ranking
RANK 1, 2, 3, 3, 5, ...
functions
for ranking
RANK 1, 2, 3, 3, 5, ...
DENSE_RANK 1, 2, 3, 3, 4, ...
functions
for ranking
functions
for ranking
RANK 1, 2, 3, 3, 5, ...
DENSE_RANK 1, 2, 3, 3, 4, ...
CUME_DIST
SQL> select ename, sal,
2 100*cume_dist() over ( order by sal ) as pct
3 from emp
4 order by sal;
ENAME SAL PCT
---------- ---------- -------
SMITH 800 7.14
JAMES 950 14.29
ADAMS 1100 21.43
WARD 1250 35.71
MARTIN 1250 35.71
MILLER 1300 42.86
TURNER 1500 50.00
ALLEN 1600 57.14
CLARK 2450 64.29
BLAKE 2850 71.43
JONES 2975 78.57
FORD 3000 92.86
SCOTT 3000 92.86
KING 5000 100.00
functions
for ranking
RANK 1, 2, 3, 3, 5, ...
DENSE_RANK 1, 2, 3, 3, 4, ...
CUME_DIST
PERCENT_RANK
SQL> select ename, sal,
2 100*percent_rank() over ( order by sal ) pct
3 from emp
4 order by ename;
ENAME SAL PCT
---------- ---------- -------
ADAMS 1100 15.38
ALLEN 1600 53.85
BLAKE 2850 69.23
CLARK 2450 61.54
FORD 3000 84.62
JAMES 950 7.69
JONES 2975 76.92
KING 5000 100.00
MARTIN 1250 23.08
MILLER 1300 38.46
SCOTT 3000 84.62
SMITH 800 .00
TURNER 1500 46.15
WARD 1250 23.08
functions
for ranking
RANK 1, 2, 3, 3, 5, ...
DENSE_RANK 1, 2, 3, 3, 4, ...
CUME_DIST
PERCENT_RANK
NTILE
SQL> select ename, sal,
2 ntile(4) over ( order by sal ) as quartile
3 from emp
4 order by ename;
ENAME SAL QUARTILE
---------- ---------- ----------
ADAMS 1100 1
ALLEN 1600 2
BLAKE 2850 3
CLARK 2450 3
FORD 3000 4
JAMES 950 1
JONES 2975 3
KING 5000 4
MARTIN 1250 2
MILLER 1300 2
SCOTT 3000 4
SMITH 800 1
TURNER 1500 2
WARD 1250 1
RANK 1, 2, 3, 3, 5, ...
DENSE_RANK 1, 2, 3, 3, 4, ...
CUME_DIST
PERCENT_RANK
NTILE
ROW_NUMBER 1, 2, 3, 4, 5, ...
functions
for ranking
functions
for aggregation
31
SUM
AVERAGE
MIN
MAX
COUNT
32
quick example #2
SQL> select deptno, empno, ename, job, sal
2 from emp
3 order by deptno, empno;
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7369 SMITH CLERK 800
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
30 7499 ALLEN SALESMAN 1600
30 7521 WARD SALESMAN 1250
30 7654 MARTIN SALESMAN 1250
30 7698 BLAKE MANAGER 2850
30 7844 TURNER SALESMAN 1500
30 7900 JAMES CLERK 950
34
"department salaries,
running total
by employee name"
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7369 SMITH CLERK 800
30 7499 ALLEN SALESMAN 1600
30 7698 BLAKE MANAGER 2850
30 7900 JAMES CLERK 950
30 7654 MARTIN SALESMAN 1250
30 7844 TURNER SALESMAN 1500
30 7521 WARD SALESMAN 1250
RUNNING_TOTAL
-------------
2450
7450
8750
1100
4100
7075
10075
10875
1600
4450
5400
6650
8150
9400
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, ename;
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7369 SMITH CLERK 800
30 7499 ALLEN SALESMAN 1600
30 7698 BLAKE MANAGER 2850
30 7900 JAMES CLERK 950
30 7654 MARTIN SALESMAN 1250
30 7844 TURNER SALESMAN 1500
30 7521 WARD SALESMAN 1250
RUNNING_TOTAL
-------------
2450
7450
8750
1100
4100
7075
10075
10875
1600
4450
5400
6650
8150
9400
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, ename;
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7369 SMITH CLERK 800
30 7499 ALLEN SALESMAN 1600
30 7698 BLAKE MANAGER 2850
30 7900 JAMES CLERK 950
30 7654 MARTIN SALESMAN 1250
30 7844 TURNER SALESMAN 1500
30 7521 WARD SALESMAN 1250
RUNNING_TOTAL
-------------
2450
7450
8750
1100
4100
7075
10075
10875
1600
4450
5400
6650
8150
9400
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, ename;
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7369 SMITH CLERK 800
30 7499 ALLEN SALESMAN 1600
30 7698 BLAKE MANAGER 2850
30 7900 JAMES CLERK 950
30 7654 MARTIN SALESMAN 1250
30 7844 TURNER SALESMAN 1500
30 7521 WARD SALESMAN 1250
RUNNING_TOTAL
-------------
2450
7450
8750
1100
4100
7075
10075
10875
1600
4450
5400
6650
8150
9400
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, ename;
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7369 SMITH CLERK 800
30 7499 ALLEN SALESMAN 1600
30 7698 BLAKE MANAGER 2850
30 7900 JAMES CLERK 950
30 7654 MARTIN SALESMAN 1250
30 7844 TURNER SALESMAN 1500
30 7521 WARD SALESMAN 1250
RUNNING_TOTAL
-------------
2450
7450
8750
1100
4100
7075
10075
10875
1600
4450
5400
6650
8150
9400
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, ename;
sum(sal) OVER (
partition by deptno
order by ename) as running_total
function
sorting clause
partition clause
41
be careful
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7369 SMITH CLERK 800
30 7499 ALLEN SALESMAN 1600
30 7698 BLAKE MANAGER 2850
30 7900 JAMES CLERK 950
30 7654 MARTIN SALESMAN 1250
30 7844 TURNER SALESMAN 1500
30 7521 WARD SALESMAN 1250
RUNNING_TOTAL
-------------
2450
7450
8750
1100
4100
7075
10075
10875
1600
4450
5400
6650
8150
9400
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, ename;
SQL> select deptno, empno, ename, job, sal
2 from emp
3 order by deptno, hiredate;
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7369 SMITH CLERK 800
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
30 7499 ALLEN SALESMAN 1600
30 7521 WARD SALESMAN 1250
30 7654 MARTIN SALESMAN 1250
30 7698 BLAKE MANAGER 2850
30 7844 TURNER SALESMAN 1500
30 7900 JAMES CLERK 950
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, hiredate
RUNNING_TOTAL
-------------
2450
7450
8750
10875
7075
10075
1100
4100
1600
9400
6650
4450
8150
5400
44
lots of power
SQL> select deptno, job, ename, sal,
2 sum(sal) over () total_sal,
3 sum(sal) over
4 ( partition by deptno) sal_by_dept,
5 sum(sal) over
6 ( partition by deptno, job) sal_by_dept_job
7 from emp
8 order by deptno, job;
DEPTNO JOB ENAME SAL
---------- --------- ---------- ----------
10 CLERK MILLER 1300
10 MANAGER CLARK 2450
10 PRESIDENT KING 5000
20 ANALYST SCOTT 3000
20 ANALYST FORD 3000
20 CLERK ADAMS 1100
20 CLERK SMITH 800
20 MANAGER JONES 2975
30 CLERK JAMES 950
30 MANAGER BLAKE 2850
30 SALESMAN TURNER 1500
30 SALESMAN MARTIN 1250
30 SALESMAN WARD 1250
30 SALESMAN ALLEN 1600
TOTAL_SAL
----------
29025
29025
29025
29025
29025
29025
29025
29025
29025
29025
29025
29025
29025
29025
SAL_BY_DEPT
-----------
8750
8750
8750
10875
10875
10875
10875
10875
9400
9400
9400
9400
9400
9400
SAL_BY_DEPT_JOB
---------------
1300
2450
5000
6000
6000
1900
1900
2975
950
2850
5600
5600
5600
5600
and a whole lot more...
COLLECT
CORR
COVAR_POP
COVAR_SAMP
GROUP_ID
GROUPING
GROUPING_ID
MEDIAN
PERCENTILE_CONT
PERCENTILE_DISC
REGR_ ...
STATS_BINOMIAL_TEST
STATS_KS_TEST
STATS_MODE
STATS_MW_TEST
STATS_ONE_WAY_ANOVA
STATS_F_TEST
STATS_CROSSTAB
STATS_T_TEST_...
STATS_WSR_TEST
STDDEV
STDDEV_POP
STDDEV_SAMP VAR_POP
VAR_SAMP
VARIANCE
47
there is a cost
48
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER ( ... ),
3 max(hiredate) over ( ... ),
4 stddev(commission) over ( .... )
...
...
...
25 from emp
49
a lot of work
50
and a little surprise...
51
SQL> select deptno, empno, ename, job, sal
2 from emp
3 order by deptno, empno;
----------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 12 | 1044 | 4 (25)|
| 1 | SORT ORDER BY | | 12 | 1044 | 4 (25)|
| 2 | TABLE ACCESS FULL| EMP | 12 | 1044 | 3 (0)|
----------------------------------------------------------------
52
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
6 order by deptno, empno
----------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 12 | 468 | 3 (0)|
| 1 | WINDOW SORT | | 12 | 468 | 3 (0)|
| 2 | TABLE ACCESS FULL| EMP | 12 | 468 | 3 (0)|
----------------------------------------------------------------
53
some possible sorting anomalies
MOS
workarea_size_policy
_smm_isort_cap
_smm_max_size
_newsort_enabled
_smm_auto_min_io_size
_smm_auto_max_io_size
Current versions should all be fine
55
important note !!!
56
aggregations
57
calculated
not
consolidative
58
conventional aggregation
59
SQL> select deptno, sum(sal)
2 from emp
3 group by deptno;
DEPTNO SUM(SAL)
---------- ----------
10 8750
20 10875
30 9400
60
SQL> select ename, deptno,
2 sum(sal) over
3 ( partition by deptno) as deptsal
4 from emp
5 order by deptno;
ENAME DEPTNO DEPTSAL
---------- ---------- ----------
CLARK 10 8750
KING 10 8750
MILLER 10 8750
JONES 20 10875
FORD 20 10875
ADAMS 20 10875
SMITH 20 10875
SCOTT 20 10875
WARD 30 9400
TURNER 30 9400
ALLEN 30 9400
JAMES 30 9400
BLAKE 30 9400
MARTIN 30 9400
still 14 rows !!!
61
two kinds
62
aggregation
63
reporting
aggregation
"same aggregate for each row in a partition"
64
SQL> select ename, deptno,
2 sum(sal) over ( partition by deptno) as deptsal
3 from emp
4 order by deptno;
ENAME DEPTNO DEPTSAL
---------- ---------- ----------
CLARK 10 8750
KING 10 8750
MILLER 10 8750
JONES 20 10875
FORD 20 10875
ADAMS 20 10875
SMITH 20 10875
SCOTT 20 10875
WARD 30 9400
TURNER 30 9400
ALLEN 30 9400
JAMES 30 9400
BLAKE 30 9400
MARTIN 30 9400
same for
each row
in partition
65
windowing
aggregation
"changing aggregate for each row in a partition"
<function> ( <arg>,<arg>,… )
OVER (
<partition clause>
<sorting clause>
<windowing clause>
)
defines how broadly the
aggregating function applies
67
"show me a salary running total"
SQL> select
2 empno, ename, sal,
3 sum(sal)
4 over ( order by empno
5 rows between unbounded preceding and current row ) as cumtot
6 from emp
7 order by empno;
EMPNO ENAME SAL CUMTOT
---------- ---------- ---------- ----------
7369 SMITH 800 800
7499 ALLEN 1600 2400
7521 WARD 1250 3650
7566 JONES 2975 6625
7654 MARTIN 1250 7875
7698 BLAKE 2850 10725
7782 CLARK 2450 13175
7788 SCOTT 3000 16175
7839 KING 5000 21175
7844 TURNER 1500 22675
7876 ADAMS 1100 23775
7900 JAMES 950 24725
7902 FORD 3000 27725
7934 MILLER 1300 29025
SQL> select
2 empno, ename, sal,
3 sum(sal)
4 over ( order by empno
5 rows between unbounded preceding and current row ) as cumtot
6 from emp
7 order by empno;
EMPNO ENAME SAL CUMTOT
---------- ---------- ---------- ----------
7369 SMITH 800 800
7499 ALLEN 1600 2400
7521 WARD 1250 3650
7566 JONES 2975 6625
7654 MARTIN 1250 7875
7698 BLAKE 2850 10725
7782 CLARK 2450 13175
7788 SCOTT 3000 16175
7839 KING 5000 21175
7844 TURNER 1500 22675
7876 ADAMS 1100 23775
7900 JAMES 950 24725
7902 FORD 3000 27725
7934 MILLER 1300 29025
SQL> select
2 empno, ename, sal,
3 sum(sal)
4 over ( order by empno
5 rows between unbounded preceding and current row ) as cumtot
6 from emp
7 order by empno;
EMPNO ENAME SAL CUMTOT
---------- ---------- ---------- ----------
7369 SMITH 800 800
7499 ALLEN 1600 2400
7521 WARD 1250 3650
7566 JONES 2975 6625
7654 MARTIN 1250 7875
7698 BLAKE 2850 10725
7782 CLARK 2450 13175
7788 SCOTT 3000 16175
7839 KING 5000 21175
7844 TURNER 1500 22675
7876 ADAMS 1100 23775
7900 JAMES 950 24725
7902 FORD 3000 27725
7934 MILLER 1300 29025
SQL> select
2 empno, ename, sal,
3 sum(sal)
4 over ( order by empno
5 rows between unbounded preceding and current row ) as cumtot
6 from emp
7 order by empno;
EMPNO ENAME SAL CUMTOT
---------- ---------- ---------- ----------
7369 SMITH 800 800
7499 ALLEN 1600 2400
7521 WARD 1250 3650
7566 JONES 2975 6625
7654 MARTIN 1250 7875
7698 BLAKE 2850 10725
7782 CLARK 2450 13175
7788 SCOTT 3000 16175
7839 KING 5000 21175
7844 TURNER 1500 22675
7876 ADAMS 1100 23775
7900 JAMES 950 24725
7902 FORD 3000 27725
7934 MILLER 1300 29025
72
"give me the sum across 3 rows, ie,
one before and one after"
SQL> select deptno, ename, hiredate, sal,
2 sum(sal) over (
3 partition by deptno
4 order by hiredate
5 rows between 1 preceding and 1 following) as x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- ----------
10 CLARK 09-JUN-81 2450 7450
10 KING 17-NOV-81 5000 8750
10 MILLER 23-JAN-82 1300 6300
20 SMITH 17-DEC-80 800 3775
20 JONES 02-APR-81 2975 6775
20 FORD 03-DEC-81 3000 8975
20 SCOTT 09-DEC-82 3000 7100
20 ADAMS 12-JAN-83 1100 4100
30 ALLEN 20-FEB-81 1600 2850
30 WARD 22-FEB-81 1250 5700
30 BLAKE 01-MAY-81 2850 5600
30 TURNER 08-SEP-81 1500 5600
30 MARTIN 28-SEP-81 1250 3700
30 JAMES 03-DEC-81 950 2200
SQL> select deptno, ename, hiredate, sal,
2 sum(sal) over (
3 partition by deptno
4 order by hiredate
5 rows between 1 preceding and 1 following) as x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- ----------
10 CLARK 09-JUN-81 2450 7450
10 KING 17-NOV-81 5000 8750
10 MILLER 23-JAN-82 1300 6300
20 SMITH 17-DEC-80 800 3775
20 JONES 02-APR-81 2975 6775
20 FORD 03-DEC-81 3000 8975
20 SCOTT 09-DEC-82 3000 7100
20 ADAMS 12-JAN-83 1100 4100
30 ALLEN 20-FEB-81 1600 2850
30 WARD 22-FEB-81 1250 5700
30 BLAKE 01-MAY-81 2850 5600
30 TURNER 08-SEP-81 1500 5600
30 MARTIN 28-SEP-81 1250 3700
30 JAMES 03-DEC-81 950 2200
SQL> select deptno, ename, hiredate, sal,
2 sum(sal) over (
3 partition by deptno
4 order by hiredate
5 rows between 1 preceding and 1 following) as x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- ----------
10 CLARK 09-JUN-81 2450 7450
10 KING 17-NOV-81 5000 8750
10 MILLER 23-JAN-82 1300 6300
20 SMITH 17-DEC-80 800 3775
20 JONES 02-APR-81 2975 6775
20 FORD 03-DEC-81 3000 8975
20 SCOTT 09-DEC-82 3000 7100
20 ADAMS 12-JAN-83 1100 4100
30 ALLEN 20-FEB-81 1600 2850
30 WARD 22-FEB-81 1250 5700
30 BLAKE 01-MAY-81 2850 5600
30 TURNER 08-SEP-81 1500 5600
30 MARTIN 28-SEP-81 1250 3700
30 JAMES 03-DEC-81 950 2200
SQL> select deptno, ename, hiredate, sal,
2 sum(sal) over (
3 partition by deptno
4 order by hiredate
5 rows between 1 preceding and 1 following) as x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- ----------
10 CLARK 09-JUN-81 2450 7450
10 KING 17-NOV-81 5000 8750
10 MILLER 23-JAN-82 1300 6300
20 SMITH 17-DEC-80 800 3775
20 JONES 02-APR-81 2975 6775
20 FORD 03-DEC-81 3000 8975
20 SCOTT 09-DEC-82 3000 7100
20 ADAMS 12-JAN-83 1100 4100
30 ALLEN 20-FEB-81 1600 2850
30 WARD 22-FEB-81 1250 5700
30 BLAKE 01-MAY-81 2850 5600
30 TURNER 08-SEP-81 1500 5600
30 MARTIN 28-SEP-81 1250 3700
30 JAMES 03-DEC-81 950 2200
77
"I need a 6 month moving average"
SQL> select deptno, ename, hiredate, sal,
2 avg(sal) over (
3 partition by deptno
4 order by hiredate
5 range between interval '6' month preceding and current row ) x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- --------
10 CLARK 09-JUN-81 2450 2450
10 KING 17-NOV-81 5000 3725
10 MILLER 23-JAN-82 1300 3150
20 SMITH 17-DEC-80 800 800
20 JONES 02-APR-81 2975 1888
20 FORD 03-DEC-81 3000 3000
20 SCOTT 09-DEC-82 3000 3000
20 ADAMS 12-JAN-83 1100 2050
30 ALLEN 20-FEB-81 1600 1600
30 WARD 22-FEB-81 1250 1425
30 BLAKE 01-MAY-81 2850 1900
30 TURNER 08-SEP-81 1500 2175
30 MARTIN 28-SEP-81 1250 1867
30 JAMES 03-DEC-81 950 1233
SQL> select deptno, ename, hiredate, sal,
2 avg(sal) over (
3 partition by deptno
4 order by hiredate
5 range between interval '6' month preceding and current row ) x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- --------
10 CLARK 09-JUN-81 2450 2450
10 KING 17-NOV-81 5000 3725
10 MILLER 23-JAN-82 1300 3150
20 SMITH 17-DEC-80 800 800
20 JONES 02-APR-81 2975 1888
20 FORD 03-DEC-81 3000 3000
20 SCOTT 09-DEC-82 3000 3000
20 ADAMS 12-JAN-83 1100 2050
30 ALLEN 20-FEB-81 1600 1600
30 WARD 22-FEB-81 1250 1425
30 BLAKE 01-MAY-81 2850 1900
30 TURNER 08-SEP-81 1500 2175
30 MARTIN 28-SEP-81 1250 1867
30 JAMES 03-DEC-81 950 1233
SQL> select deptno, ename, hiredate, sal,
2 avg(sal) over (
3 partition by deptno
4 order by hiredate
5 range between interval '6' month preceding and current row ) x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- --------
10 CLARK 09-JUN-81 2450 2450
10 KING 17-NOV-81 5000 3725
10 MILLER 23-JAN-82 1300 3150
20 SMITH 17-DEC-80 800 800
20 JONES 02-APR-81 2975 1888
20 FORD 03-DEC-81 3000 3000
20 SCOTT 09-DEC-82 3000 3000
20 ADAMS 12-JAN-83 1100 2050
30 ALLEN 20-FEB-81 1600 1600
30 WARD 22-FEB-81 1250 1425
30 BLAKE 01-MAY-81 2850 1900
30 TURNER 08-SEP-81 1500 2175
30 MARTIN 28-SEP-81 1250 1867
30 JAMES 03-DEC-81 950 1233
SQL> select deptno, ename, hiredate, sal,
2 avg(sal) over (
3 partition by deptno
4 order by hiredate
5 range between interval '6' month preceding and current row ) x
6 from emp
7 order by deptno, hiredate;
DEPTNO ENAME HIREDATE SAL X
---------- ---------- --------- ---------- --------
10 CLARK 09-JUN-81 2450 2450
10 KING 17-NOV-81 5000 3725
10 MILLER 23-JAN-82 1300 3150
20 SMITH 17-DEC-80 800 800
20 JONES 02-APR-81 2975 1888
20 FORD 03-DEC-81 3000 3000
20 SCOTT 09-DEC-82 3000 3000
20 ADAMS 12-JAN-83 1100 2050
30 ALLEN 20-FEB-81 1600 1600
30 WARD 22-FEB-81 1250 1425
30 BLAKE 01-MAY-81 2850 1900
30 TURNER 08-SEP-81 1500 2175
30 MARTIN 28-SEP-81 1250 1867
30 JAMES 03-DEC-81 950 1233
82
windows can be dynamic
83
"I need the sum sales from
the previous week day "
SQL> create or replace
2 function LAST_CLOSE(p_purchase_date date)
3 return number is
4 begin
5 return
6 case to_char(p_purchase_date,'DY')
7 when 'SUN' then 2 -- Fri,Sat
8 when 'MON' then 3 -- Fri,Sat,Sun
9 else 1
10 end;
11 end;
12 /
Function created.
SQL> select
2 prod_id, cust_id,
3 sum(amount_sold)
4 over ( order by purchase_date
5 range between LAST_CLOSE(purchase_date) preceding) as bus_tot
6 from sales
7 /
85
window boundaries
86
first_value / last_value
87
"compare each salary with first
person hired across entire organisation
and within each department"
SQL> select deptno, hiredate, empno, ename, sal,
2 first_value(sal) over ( order by hiredate
3 range unbounded preceding ) lo_sal,
4 first_value(sal) over ( partition by deptno
5 order by hiredate
6 range unbounded preceding) lo_dept_sal
7 from emp
8 order by deptno, hiredate;
DEPTNO HIREDATE EMPNO ENAME SAL
---------- --------- ---------- ---------- ----------
10 09-JUN-81 7782 CLARK 2450
10 17-NOV-81 7839 KING 5000
10 23-JAN-82 7934 MILLER 1300
20 17-DEC-80 7369 SMITH 800
20 02-APR-81 7566 JONES 2975
20 03-DEC-81 7902 FORD 3000
20 09-DEC-82 7788 SCOTT 3000
20 12-JAN-83 7876 ADAMS 1100
30 20-FEB-81 7499 ALLEN 1600
30 22-FEB-81 7521 WARD 1250
30 01-MAY-81 7698 BLAKE 2850
30 08-SEP-81 7844 TURNER 1500
30 28-SEP-81 7654 MARTIN 1250
30 03-DEC-81 7900 JAMES 950
LO_SAL
----------
800
800
800
800
800
800
800
800
800
800
800
800
800
800
LO_DEPT_SAL
-----------
2450
2450
2450
800
800
800
800
800
1600
1600
1600
1600
1600
1600
89
beyond first and last
90
nth_value
91
"compare each salary with second hired
person across entire organisation
and within each department"
SQL> select deptno, hiredate, empno, ename, sal,
2 100 * sal / nth_value(sal,2) over ( order by hiredate
3 range unbounded preceding ) sal_pct,
4 100 * sal / nth_value(sal,2) over ( partition by deptno
5 order by hiredate
6 range unbounded preceding) dept_sal_pct
7 from emp
8 order by deptno, hiredate;
DEPTNO HIREDATE EMPNO ENAME SAL
---------- --------- ---------- ---------- ----------
10 09-JUN-81 7782 CLARK 2450
10 17-NOV-81 7839 KING 5000
10 23-JAN-82 7934 MILLER 1300
20 17-DEC-80 7369 SMITH 800
20 02-APR-81 7566 JONES 2975
20 03-DEC-81 7902 FORD 3000
20 09-DEC-82 7788 SCOTT 3000
20 12-JAN-83 7876 ADAMS 1100
30 20-FEB-81 7499 ALLEN 1600
30 22-FEB-81 7521 WARD 1250
30 01-MAY-81 7698 BLAKE 2850
30 08-SEP-81 7844 TURNER 1500
30 28-SEP-81 7654 MARTIN 1250
30 03-DEC-81 7900 JAMES 950
SAL_PCT
-------
153.13
312.50
81.25
185.94
187.50
187.50
68.75
100.00
78.13
178.13
93.75
78.13
59.38
DEPT_SAL_PCT
------------
100.00
26.00
100.00
100.84
100.84
36.97
100.00
228.00
120.00
100.00
76.00
93
ignore nulls extension
SQL> select empno, ename, sal, deptno
2 from emp
3 order by sal;
EMPNO ENAME SAL DEPTNO
---------- ---------- ---------- ----------
7369 SMITH 800 10
7900 JAMES 950
7876 ADAMS 1100
7521 WARD 1250 20
7654 MARTIN 1250
7934 MILLER 1300
7844 TURNER 1500
7499 ALLEN 1600 30
7782 CLARK 2450
7698 BLAKE 2850
7566 JONES 2975
7788 SCOTT 3000
7902 FORD 3000
7839 KING 5000 40
SQL> select empno, ename, sal, deptno,
2 last_value(deptno IGNORE NULLS)
3 over (order by sal) as last_dept
4 from emp
5 order by sal
EMPNO ENAME SAL DEPTNO
---------- ---------- ---------- ----------
7369 SMITH 800 10
7900 JAMES 950
7876 ADAMS 1100
7521 WARD 1250 20
7654 MARTIN 1250
7934 MILLER 1300
7844 TURNER 1500
7499 ALLEN 1600 30
7782 CLARK 2450
7698 BLAKE 2850
7566 JONES 2975
7788 SCOTT 3000
7902 FORD 3000
7839 KING 5000 40
LAST_DEPT
----------
10
10
10
20
20
20
20
30
30
30
30
30
30
40
SQL> select last_dept, count(*)
2 from
3 ( select
4 last_value(deptno ignore nulls)
5 over (order by sal) as last_dept
6 from emp2
7 )
8 group by last_dept;
LAST_DEPT COUNT(*)
---------- ----------
30 6
20 4
40 1
10 3
97
implicit windows
98
recall
SQL> select ename, deptno,
2 sum(sal) over ( partition by deptno ) as deptsal
3 from emp
4 order by deptno;
ENAME DEPTNO DEPTSAL
---------- ---------- ----------
CLARK 10 8750
KING 10 8750
MILLER 10 8750
JONES 20 10875
FORD 20 10875
ADAMS 20 10875
SMITH 20 10875
SCOTT 20 10875
WARD 30 9400
TURNER 30 9400
ALLEN 30 9400
JAMES 30 9400
BLAKE 30 9400
MARTIN 30 9400
reporting
aggregate
DEPTNO EMPNO ENAME JOB SAL
---------- ---------- ---------- --------- ----------
10 7782 CLARK MANAGER 2450
10 7839 KING PRESIDENT 5000
10 7934 MILLER CLERK 1300
20 7876 ADAMS CLERK 1100
20 7902 FORD ANALYST 3000
20 7566 JONES MANAGER 2975
20 7788 SCOTT ANALYST 3000
20 7369 SMITH CLERK 800
30 7499 ALLEN SALESMAN 1600
30 7698 BLAKE MANAGER 2850
30 7900 JAMES CLERK 950
30 7654 MARTIN SALESMAN 1250
30 7844 TURNER SALESMAN 1500
30 7521 WARD SALESMAN 1250
RUNNING_TOTAL
-------------
2450
7450
8750
1100
4100
7075
10075
10875
1600
4450
5400
6650
8150
9400
SQL> select deptno, empno, ename, job, sal,
2 sum(sal) OVER (
3 partition by deptno
4 order by ename) as running_total
5 from emp
windowing aggregate
<function> ( <arg>,<arg>,… )
OVER (
<partition clause>
<sorting clause>
<windowing clause>
)
but I didn't specify
one of these ?
<function> ( <arg>,<arg>,… )
OVER (
<partition clause>
<sorting clause>
<windowing clause>
)
THEN you get one of
these automatically !
IF this is an
aggregate function ...
AND you have included
an ORDER BY clause ...
range between unbounded preceding and current row
sum(sal) OVER (
partition by deptno
)
function
partition clause
order by ename
104
"OVER"
105
lag / lead
SQL> select
2 empno, ename, hiredate, sal,
3 lag(sal,1)
4 over ( order by hiredate ) prev_hire_sal
5 from emp
6 order by hiredate;
EMPNO ENAME HIREDATE SAL
---------- ---------- --------- ----------
7369 SMITH 17-DEC-80 800
7499 ALLEN 20-FEB-81 1600
7521 WARD 22-FEB-81 1250
7566 JONES 02-APR-81 2975
7698 BLAKE 01-MAY-81 2850
7782 CLARK 09-JUN-81 2450
7844 TURNER 08-SEP-81 1500
7654 MARTIN 28-SEP-81 1250
7839 KING 17-NOV-81 5000
7900 JAMES 03-DEC-81 950
7902 FORD 03-DEC-81 3000
7934 MILLER 23-JAN-82 1300
7788 SCOTT 09-DEC-82 3000
7876 ADAMS 12-JAN-83 1100
PREV_HIRE_SAL
--------------
800
1600
1250
2975
2850
2450
1500
1250
5000
950
3000
1300
3000
107
ignore nulls as well
108
by default
SQL> select empno, ename, sal
2 from emp
3 order by empno;
EMPNO ENAME SAL
---------- ---------- ----------
7369 SMITH 800
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN 1250
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING 5000
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
SQL> select empno, ename, sal,
2 lag(sal,1)
3 over ( order by empno) as prev_sal
4 from emp
5 order by empno;
EMPNO ENAME SAL PREV_SAL
---------- ---------- ---------- ----------
7369 SMITH 800
7499 ALLEN 800
7521 WARD
7566 JONES
7654 MARTIN 1250
7698 BLAKE 1250
7782 CLARK
7788 SCOTT
7839 KING 5000
7844 TURNER 5000
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
SQL> select empno, ename, sal,
2 lag(sal,1) ignore nulls
3 over ( order by empno) as prev_sal
4 from emp
5 order by empno;
EMPNO ENAME SAL
---------- ---------- ----------
7369 SMITH 800
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN 1250
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING 5000
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
PREV_SAL
----------
800
800
800
800
1250
1250
1250
1250
5000
5000
5000
5000
5000
112
and then....
113
“imagination is more
important than knowledge”
- Albert Einstein
114
not just warehousing
115
classical problems
made simple
116
"remove the duplicates"
SQL> select * from BAD_EMP;
EMPNO ENAME JOB MGR HIREDATE SAL
---------- ---------- --------- ---------- --------- ----------
7788 SCOTT ANALYST 7566 09-DEC-82 3000
7499 ALLEN SALESMAN 7698 20-FEB-81 1600
7369 SMITH CLERK 7902 17-DEC-80 800
7839 KING PRESIDENT 17-NOV-81 5000
7566 JONES MANAGER 7839 02-APR-81 2975
7876 ADAMS CLERK 7788 12-JAN-83 1100
7844 TURNER SALESMAN 7698 08-SEP-81 1500
7499 ALLEN SALESMAN 7698 20-FEB-81 1600
7369 SMITH CLERK 7902 17-DEC-80 800
7902 FORD ANALYST 7566 03-DEC-81 3000
7900 JAMES CLERK 7698 03-DEC-81 950
7521 WARD SALESMAN 7698 22-FEB-81 1250
7654 MARTIN SALESMAN 7698 28-SEP-81 1250
7934 MILLER CLERK 7782 23-JAN-82 1300
7698 BLAKE MANAGER 7839 01-MAY-81 2850
7782 CLARK MANAGER 7839 09-JUN-81 2450
SQL> select * from BAD_EMP;
EMPNO ENAME JOB MGR HIREDATE SAL
---------- ---------- --------- ---------- --------- ----------
7788 SCOTT ANALYST 7566 09-DEC-82 3000
7499 ALLEN SALESMAN 7698 20-FEB-81 1600
7369 SMITH CLERK 7902 17-DEC-80 800
7839 KING PRESIDENT 17-NOV-81 5000
7566 JONES MANAGER 7839 02-APR-81 2975
7876 ADAMS CLERK 7788 12-JAN-83 1100
7844 TURNER SALESMAN 7698 08-SEP-81 1500
7499 ALLEN SALESMAN 7698 20-FEB-81 1600
7369 SMITH CLERK 7902 17-DEC-80 800
7902 FORD ANALYST 7566 03-DEC-81 3000
7900 JAMES CLERK 7698 03-DEC-81 950
7521 WARD SALESMAN 7698 22-FEB-81 1250
7654 MARTIN SALESMAN 7698 28-SEP-81 1250
7934 MILLER CLERK 7782 23-JAN-82 1300
7698 BLAKE MANAGER 7839 01-MAY-81 2850
7782 CLARK MANAGER 7839 09-JUN-81 2450
SQL> select empno, rowid,
2 row_number() over
3 ( partition by empno order by rowid ) as r
4 from BAD_EMP
5 /
EMPNO ROWID R
---------- ------------------ ----------
7369 AAARXwAAEAAATlMAAA 1
7369 AAARXwAAEAAATlOAAA 2
7499 AAARXwAAEAAATlMAAB 1
7499 AAARXwAAEAAATlOAAB 2
7521 AAARXwAAEAAATlMAAC 1
7566 AAARXwAAEAAATlMAAD 1
7654 AAARXwAAEAAATlMAAE 1
7698 AAARXwAAEAAATlMAAF 1
7782 AAARXwAAEAAATlMAAG 1
7788 AAARXwAAEAAATlMAAH 1
7839 AAARXwAAEAAATlMAAI 1
7844 AAARXwAAEAAATlMAAJ 1
7876 AAARXwAAEAAATlMAAK 1
7900 AAARXwAAEAAATlMAAL 1
7902 AAARXwAAEAAATlMAAM 1
7934 AAARXwAAEAAATlMAAN 1
SQL> delete from BAD_EMP
2 where ROWID in
3 ( select rowid
4 from
5 ( select rowid,
6 row_number() over
7 ( partition by empno
8 order by rowid) as r
9 from BAD_EMP
10 )
11 where r > 1
12 )
13 /
2 rows deleted.
121
“5 highest salaries
from each department”
SQL> select deptno, salary
2 from
3 ( select
4 deptno,
5 salary,
6 rank() over (
7 partition by deptno
8 order by salary) top_5
9 from EMPLOYEES
10 )
11 where top_5 <= 5
123
“mind the gap”
124
SQL> select X from T;
X
----------
2
3
4
7
8
12
13
15
16
17
19
20
2-4
7-8
12-13
15-17
19-20
125
SQL> select
2 x,
3 lag(x) over ( order by x) prev
4 from T ;
X PREV
---------- ----------
2
3 2
4 3
7 4
8 7
12 8
13 12
15 13
16 15
17 16
19 17
20 19
126
SQL> select
2 x,
3 lag(x) over ( order by x) prev
4 from T ;
X PREV
---------- ----------
2
3 2
4 3
7 4
8 7
12 8
13 12
15 13
16 15
17 16
19 17
20 19
127
SQL> select
2 x,
3 lag(x) over ( order by x) prev
4 from T ;
X PREV
---------- ----------
2
3 2
4 3
7 4
8 7
12 8
13 12
15 13
16 15
17 16
19 17
20 19
128
SQL> select
2 x,
3 lag(x) over ( order by x) prev
4 from T ;
X PREV
---------- ----------
2
3 2
4 3
7 4
8 7
12 8
13 12
15 13
16 15
17 16
19 17
20 19
129
SQL> select
2 x,
3 lag(x) over ( order by x) prev
4 from T ;
X PREV
---------- ----------
2
3 2
4 3
7 4
8 7
12 8
13 12
15 13
16 15
17 16
19 17
20 19
130
SQL> select
2 x,
3 case
4 when nvl(lag(x) over (order by x),x) != x-1
5 then x end loval
6 from t;
X LOVAL
---------- ----------
2 2
3
4
7 7
8
12 12
13
15 15
16
17
19 19
20
131
SQL> select
2 x,
3 case
4 when nvl(lag(x) over (order by x),x) != x-1
5 then x end loval
6 from t;
X LOVAL
---------- ----------
2 2
3
4
7 7
8
12 12
13
15 15
16
17
19 19
20
132
SQL> select
2 x,
3 case
4 when nvl(lag(x) over (order by x),x) != x-1
5 then x end loval
6 from t;
X LOVAL
---------- ----------
2 2
3
4
7 7
8
12 12
13
15 15
16
17
19 19
20
133
SQL> select
2 x,
3 case
4 when nvl(lag(x) over (order by x),x) != x-1
5 then x end loval
6 from t;
X LOVAL
---------- ----------
2 2
3
4
7 7
8
12 12
13
15 15
16
17
19 19
20
134
SQL> select x, max(loval) over (order by x) loval
2 from (
3 select x,
4 case
5 when nvl(lag(x) over (order by x),x) != x-1
6 then x end loval
7 from t );
X LOVAL
---------- ----------
2 2
3 2
4 2
7 7
8 7
12 12
13 12
15 15
16 15
17 15
19 19
20 19
135
SQL> select x, max(loval) over (order by x) loval
2 from (
3 select x,
4 case
5 when nvl(lag(x) over (order by x),x) != x-1
6 then x end loval
7 from t );
X LOVAL
---------- ----------
2 2
3 2
4 2
7 7
8 7
12 12
13 12
15 15
16 15
17 15
19 19
20 19
136
SQL> select min(x)||’-’||max(x) ranges from (
2 select x,max(loval) over (order by x) loval
3 from (
4 select x,
5 case
6 when nvl(lag(x) over (order by x),x) != x-1
7 then x end loval
8 from t))
9 group by loval;
RANGES
--------------------
2-4
7-8
12-13
15-17
19-20
137
or ...
138
SQL> select
2 min(x)||'-'||
3 case when min (x) = max (x)
4 then min(x)
5 else max(x)
6 end rng
7 from
8 (select X
9 , row_number() over (order by X) rn
10 from t
11 )
12 group by x - rn
13 order by min(x);
RNG
----------------
2-4
7-8
12-13
15-17
19-20
139
in-list processing
sql_string =
"select * from ACCOUNTS where ACCT_NO in ( :bindvar )"
EXEC SQL PREPARE sql_string;
ORA-01722: invalid number
123,456,789
SQL> exec :acct = '123,456,789'
SQL> select substr(:acct,
2 loc+1,nvl(
3 lead(loc) over ( order by loc ) – loc-1,
4 length(:acct)-loc)
5 ) list_as_rows
6 from (
7 select distinct (instr(:acct,',',1,level)) loc
8 from dual
9 connect by level < length(:acct)-
10 length(replace(:acct,','))+1
11 );
LIST_AS_ROWS
--------------------
123
456
789
SQL> with MY_LIST as select substr(:acct,
2 loc+1,nvl(
3 lead(loc) over ( order by loc ) – loc-1,
4 length(:acct)-loc)
5 ) val
6 from (
7 select distinct (instr(:acct,',',1,level)) loc
8 from dual
9 connect by level < length(:acct)-
10 length(replace(:acct,','))+1
11 )
12 select *
13 from ACCOUNTS
14 where ACCT_NO in ( select val from MY_LIST)
143
even more useful...
144
opposite
145
listagg
146
classical problem
147
SQL> select deptno, ename
2 from emp
3 order by 1,2;
DEPTNO ENAME
---------- ----------
10 CLARK
10 KING
10 MILLER
20 ADAMS
20 FORD
20 JONES
20 SCOTT
20 SMITH
30 ALLEN
30 BLAKE
30 JAMES
30 MARTIN
30 TURNER
30 WARD
148
DEPTNO MEMBERS
---------- -------------------------------------
10 CLARK,KING,MILLER
20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
149
what we used to do
SQL> select deptno , rtrim(ename,',') enames
2 from ( select deptno,ename,rn
3 from emp
4 model
5 partition by (deptno)
6 dimension by (
7 row_number() over
8 (partition by deptno order by ename) rn
9 )
10 measures (cast(ename as varchar2(40)) ename)
11 rules
12 ( ename[any]
13 order by rn desc = ename[cv()]||','||ename[cv()+1])
14 )
15 where rn = 1
16 order by deptno;
DEPTNO ENAMES
---------- ----------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
- Rob Van Wijk
SQL> select deptno,
2 substr(max(sys_connect_by_path(ename, ',')), 2) members
3 from (select deptno, ename,
4 row_number ()
5 over (partition by deptno order by empno) rn
6 from emp)
7 start with rn = 1
8 connect by prior rn = rn - 1
9 and prior deptno = deptno
10 group by deptno
11 /
DEPTNO MEMBERS
---------- ---------------------------------------------------------
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
20 SMITH,JONES,SCOTT,ADAMS,FORD
10 CLARK,KING,MILLER
- Anon
SQL> select deptno,
2 xmltransform
3 ( sys_xmlagg
4 ( sys_xmlgen(ename)
5 ),
6 xmltype
7 (
8 '<?xml version="1.0"?><xsl:stylesheet version="1.0"
9 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
10 <xsl:template match="/">
11 <xsl:for-each select="/ROWSET/ENAME">
12 <xsl:value-of select="text()"/>;</xsl:for-each>
13 </xsl:template>
14 </xsl:stylesheet>'
15 )
16 ).getstringval() members
17 from emp
18 group by deptno;
DEPTNO MEMBERS
---------- --------------------------------------------------------
10 CLARK;MILLER;KING;
20 SMITH;FORD;ADAMS;SCOTT;JONES;
30 ALLEN;JAMES;TURNER;BLAKE;MARTIN;WARD;
- Laurent Schneider
SQL> create or replace type string_agg_type as object
2 (
3 total varchar2(4000),
4
5 static function
6 ODCIAggregateInitialize(sctx IN OUT string_agg_type )
7 return number,
8
9 member function
10 ODCIAggregateIterate(self IN OUT string_agg_type ,
11 value IN varchar2 )
12 return number,
13
14 member function
15 ODCIAggregateTerminate(self IN string_agg_type,
16 returnValue OUT varchar2,
17 flags IN number)
18 return number,
19
20 member function
21 ODCIAggregateMerge(self IN OUT string_agg_type,
22 ctx2 IN string_agg_type)
23 return number
24 );
25 /
154
hard
155
SQL> select deptno,
2 listagg( ename, ',')
3 within group (order by empno) members
4 from emp
5 group by deptno;
DEPTNO MEMBERS
---------- -----------------------------------------
10 CLARK,KING,MILLER
20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
156
other goodies
157
KEEP extension
“Show me lowest salary for each department...”
SQL> select deptno, min(sal)
2 from emp
3 group by deptno;
“...and I need to know who has that
lowest salary as well”
SQL> select deptno, empno, min(sal)
2 from emp
3 group by deptno;
ORA-00979: not a GROUP BY expression
159
SQL> select deptno, min(sal), min(empno)
2 KEEP ( dense_rank FIRST order by sal) empno
3 from emp
4 group by deptno
5 /
DEPTNO MIN(SAL) EMPNO
---------- ---------- ----------
10 1300 7934
20 800 7369
30 950 7900
Emp 7934 has the
lowest salary in dept 10
160
inverse analytics
161
recall
162
cume_dist
163
SQL> select ename, sal,
2 100*cume_dist() over ( order by sal ) as pct
3 from emp
4 order by sal;
ENAME SAL PCT
---------- ---------- -------
SMITH 800 7.14
JAMES 950 14.29
ADAMS 1100 21.43
WARD 1250 35.71
MARTIN 1250 35.71
MILLER 1300 42.86
TURNER 1500 50.00
ALLEN 1600 57.14
CLARK 2450 64.29
BLAKE 2850 71.43
JONES 2975 78.57
FORD 3000 92.86
SCOTT 3000 92.86
KING 5000 100.00
164
"what is the 60th percentile
salary in the company?"
165
SQL> select ename, sal,
2 100*cume_dist() over ( order by sal ) as pct
3 from emp
4 order by sal;
ENAME SAL PCT
---------- ---------- -------
SMITH 800 7.14
JAMES 950 14.29
ADAMS 1100 21.43
WARD 1250 35.71
MARTIN 1250 35.71
MILLER 1300 42.86
TURNER 1500 50.00
ALLEN 1600 57.14
CLARK 2450 64.29
BLAKE 2850 71.43
JONES 2975 78.57
FORD 3000 92.86
SCOTT 3000 92.86
KING 5000 100.00
166
SQL> select ename, sal,
2 100*cume_dist() over ( order by sal ) as pct
3 from emp
4 order by sal;
ENAME SAL PCT
---------- ---------- -------
SMITH 800 7.14
JAMES 950 14.29
ADAMS 1100 21.43
WARD 1250 35.71
MARTIN 1250 35.71
MILLER 1300 42.86
TURNER 1500 50.00
ALLEN 1600 57.14
CLARK 2450 64.29
BLAKE 2850 71.43
JONES 2975 78.57
FORD 3000 92.86
SCOTT 3000 92.86
KING 5000 100.00
167
SQL> select
2 percentile_disc(0.6)
3 within group
4 (order by sal) as dicrete_pct,
5 percentile_cont(0.6)
6 within group
7 (order by sal) as continuous_pct
8 from emp;
DICRETE_PCT CONTINUOUS_PCT
----------- --------------
2450 2280
168
classical problems
made simple
169
"median salary for
each department?"
170
what we used to do
SQL> select deptno, avg(distinct sal) median
2 from
3 (select cp1.deptno, cp1.sal
4 from emp cp1, emp cp2
5 where cp1.deptno = cp2.deptno
6 group by cp1.deptno, cp1.sal
7 having sum(decode(cp1.sal, cp2.sal, 1, 0)) >=
8 abs(sum(sign(cp1.sal - cp2.sal))))
9 group by deptno
10 /
DEPTNO MEDIAN
---------- ----------
10 3725
20 2975
30 1375
40 1300
wth?
SQL> select
2 deptno,
3 percentile_cont(0.5)
4 within group (order by sal) as median
5 from emp
6 group by deptno;
SQL> select
2 deptno,
3 median(sal)
4 from emp
5 group by deptno;
DEPTNO MEDIAN(SAL)
---------- -----------
10 3725
20 2975
30 1375
40 1300
173
hypothetical analytics
174
"if I was paid $3000,
where would I rank in
each department?"
175
SQL> select
2 deptno,
3 rank(3000) within group
4 ( order by sal ) as ranking
5 from emp
6 group by deptno;
DEPTNO RANKING
---------- ----------
10 2
20 4
30 7
40 2
176
ratio_to_report
177
"salary percentage
breakdown across employees"
SQL> select
2 empno,
3 ename,
4 sal,
5 100*ratio_to_report(sal) over () as pct
6 from emp;
EMPNO ENAME SAL PCT
---------- ---------- ---------- -------
7521 WARD 1250 4.69
7566 JONES 2975 11.17
7654 MARTIN 1250 4.69
7698 BLAKE 2850 10.70
7782 CLARK 2450 9.20
7788 SCOTT 3000 11.27
7839 KING 5000 18.78
7844 TURNER 1500 5.63
7876 ADAMS 1100 4.13
7900 JAMES 950 3.57
7902 FORD 3000 11.27
7934 MILLER 1300 4.88
179
3 more things ...
not really analytic ?
180
partitioned outer join
181
SQL> select *
2 from timeslots;
HR
--
8
9
10
11
12
13
14
15
16
SQL> select *
2 from bookings;
HR ROOM WHO
------- ---------- -------
8 Room2 PETE
9 Room1 JOHN
11 Room1 MIKE
14 Room2 JILL
15 Room2 JANE
16 Room1 SAM
182
bookings by hour
conventional outer join
183
SQL> SELECT hrs.hr, t1.room, t1.who
2 from timeslots hrs
3 left outer join bookings t1
4 on hrs.hr = t1.hr
5 order by 1
HR ROOM WHO
------- ---------- ----------
8 Room2 PETE
9 Room1 JOHN
10
11 Room1 MIKE
12
13
14 Room2 JILL
15 Room2 JANE
16 Room1 SAM
184
bookings by hour per room
185
HR ROOM WHO
------- ---------- ----------
8 Room2 PETE
9
10
11
12
13
14 Room2 JILL
15 Room2 JANE
16
HR ROOM WHO
------- ---------- ----------
8
9 Room1 JOHN
10
11 Room1 MIKE
12
13
14
15
16 Room1 SAM
186
SQL> select *
2 from timeslots;
HR
--
8
9
10
11
12
13
14
15
16
x "Room 1"
x "Room 2"
...
x "Room n"
187
partitioned outer join
188
SQL> SELECT hrs.hr, t1.room, t1.who
2 FROM bookings t1
3 PARTITION BY (t1.room)
4 RIGHT OUTER JOIN timeslots ON (hrs.hr = t1.hr)
5 order by 1,2
HR ROOM WHO
--------- ---------- ----------
8 Room1
9 Room1 JOHN
10 Room1
11 Room1 MIKE
12 Room1
13 Room1
14 Room1
15 Room1
16 Room1 SAM
8 Room2 PETE
9 Room2
10 Room2
11 Room2
12 Room2
13 Room2
14 Room2 JILL
15 Room2 JANE
16 Room2
189
width_bucket
SQL> select
2 object_id,
3 width_bucket(object_id,
4 1000,
5 90000,
6 10) bucket
7 from dba_objects
OBJECT_ID BUCKET
---------- ----------
913 0
...
3231 1
...
5858 1
...
14920 2
...
42421 5
...
91635 11
< min
> max
1 .. buckets
191
limiting SQL rows
192
12c+
193
SQL> select employee_id, last_name
2 from employees
3 order by employee_id
4 fetch first 5 rows only;
195
back to analytics
196
things to note
197
cannot be a predicate
SQL> select ename, deptno, sal
2 from emp
3 where
4 sum(sal) over
5 ( partition by deptno) > 10;
sum(sal) over
*
ERROR at line 4:
ORA-00934: group function is not allowed here
199
inline view
200
SQL> select ename, deptno, sal
2 from (
3 select ename, deptno, sal,
4 sum(sal) over
5 ( partition by deptno) as deptsal
6 from emp
7 )
8 where deptsal > 10;
201
careful with views...
202
create view RANKED_ACCOUNTS as
select account_num,
customer_name,
acct_type_code,
rank() over ( order by gross_sales ) as seq
from ACCOUNTS;
indexed column
203
SQL> select * from RANKED_ACCOUNTS
2 where ACCOUNT_NUM = 12345
------------------------------------------------
| Id | Operation | Name |
------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | VIEW | RANKED_ACCOUNTS |
| 2 | WINDOW SORT | |
| 3 | TABLE ACCESS FULL| ACCOUNTS |
------------------------------------------------
204
a more holistic view
recall
SQL> select deptno,
2 listagg( ename, ',')
3 within group (order by empno)
4 from emp
5 group by deptno;
207
still challenges
208
real example
209
anti-money laundering
210
"Find 10 consecutive deposits in a
24 hour period, then
a withdrawal within three days of
the last deposit, at a different branch"
ACCT TSTAMP WTHD_TSTAMP T AMT
---------- ------------------ ------------------ - ----------
54261 25/01/13 17:20:55 D 100
54261 25/01/13 17:56:58 D 165
54261 26/01/13 11:24:14 D 30
54261 26/01/13 11:47:53 D 45
54261 26/01/13 12:59:38 D 100
54261 26/01/13 13:26:04 D 80
54261 26/01/13 14:41:09 D 50
54261 26/01/13 14:53:12 D 50
54261 26/01/13 15:15:05 D 50
54261 26/01/13 15:51:17 D 50
54261 26/01/13 16:15:02 D 120
54261 26/01/13 16:36:51 D 100
54261 26/01/13 16:55:09 D 100
54261 26/01/13 18:07:17 26/01/13 18:07:17 W -500
212
hard...
213
"analysis"

"trends" / "patterns"
214
12c
215
pattern matching
SQL> select acct, tstamp, wthd_tstamp, txn_type, amt
2 from account_txns
3 MATCH_RECOGNIZE
4 (
5 partition by acct
6 order by tstamp
7 measures
8 dep.tstamp dep_tstamp,
9 wthd.tstamp wthd_tstamp
10
11 all rows per match
12 pattern ( dep{10,} wthd )
13 define
14 dep as
15 txn_type = 'D',
16 wthd as
17 txn_type = 'W'
18 and last(dep.tstamp)-first(dep.tstamp) < interval '1' day
19 and wthd.tstamp - last(dep.tstamp) < interval '3' day
20 and wthd.loc_id != last(dep.loc_id)
21 )
SQL> select acct, tstamp, wthd_tstamp, txn_type, amt
2 from account_txns
3 MATCH_RECOGNIZE
4 (
5 partition by acct
6 order by tstamp
7 measures
8 dep.tstamp dep_tstamp,
9 wthd.tstamp wthd_tstamp
10
11 all rows per match
12 pattern ( dep{10,} wthd )
13 define
14 dep as
15 txn_type = 'D',
16 wthd as
17 txn_type = 'W'
18 and last(dep.tstamp)-first(dep.tstamp) < interval '1' day
19 and wthd.tstamp - last(dep.tstamp) < interval '3' day
20 and wthd.loc_id != last(dep.loc_id)
21 )
SQL> select acct, tstamp, wthd_tstamp, txn_type, amt
2 from account_txns
3 MATCH_RECOGNIZE
4 (
5 partition by acct
6 order by tstamp
7 measures
8 dep.tstamp dep_tstamp,
9 wthd.tstamp wthd_tstamp
10
11 all rows per match
12 pattern ( dep{10,} wthd )
13 define
14 dep as
15 txn_type = 'D',
16 wthd as
17 txn_type = 'W'
18 and last(dep.tstamp)-first(dep.tstamp) < interval '1' day
19 and wthd.tstamp - last(dep.tstamp) < interval '3' day
20 and wthd.loc_id != last(dep.loc_id)
21 )
219
wrap up
220
analytics
221
super cool
222
super powerful
223
less code
224
easier to read code
225
Thank you
youtube bit.ly/youtube-connor
blog bit.ly/blog-connor
twitter bit.ly/twitter-connor

More Related Content

PDF
UKOUG - 25 years of hints and tips
DOCX
Oracle 19c initialization parameters
PPT
Db2
PDF
Oracle Performance Tuning Fundamentals
PDF
Long live to CMAN!
PDF
Cluster Health Advisor (CHA) Deep Dive by Mark Scardina
PDF
TechEvent 2019: Uses of Row Pattern Matching; Kim Berg Hansen - Trivadis
PPTX
What’s New in Oracle Database 19c - Part 1
UKOUG - 25 years of hints and tips
Oracle 19c initialization parameters
Db2
Oracle Performance Tuning Fundamentals
Long live to CMAN!
Cluster Health Advisor (CHA) Deep Dive by Mark Scardina
TechEvent 2019: Uses of Row Pattern Matching; Kim Berg Hansen - Trivadis
What’s New in Oracle Database 19c - Part 1

What's hot (20)

PDF
Best practices for large oracle apps r12 implementations apps14
PDF
DBA 3 year Interview Questions
PPTX
z/OS SMPE Software Control PART 1 & PART2.pptx
PDF
Ibm db2 interview questions and answers
PPTX
Resource Access Control Facility (RACF) in Mainframes
PDF
Tuning Autovacuum in Postgresql
PDF
Oracle Database SQL Tuning Concept
PDF
PostgreSQL and RAM usage
PDF
TFA Collector - what can one do with it
PPTX
しばちょう先生が語る!オラクルデータベースの進化の歴史と最新技術動向#3
PDF
Optimizing InfluxDB Performance in the Real World by Dean Sheehan, Senior Dir...
PPTX
Security of Oracle EBS - How I can Protect my System (UKOUG APPS 18 edition)
PDF
ICE: The ultimate way of beating NAT in SIP
PDF
PPTX
Enable GoldenGate Monitoring with OEM 12c/JAgent
PDF
Oracle RAC 12c Practical Performance Management and Tuning OOW13 [CON8825]
PDF
RACF - The Basics (v1.2)
PDF
MAA for Oracle Database, Exadata and the Cloud
PDF
Db2 for z os trends
PDF
Oracle zdm Migrate Amazon RDS Oracle to Oracle Autonomous 2021 Kamalesh Ramas...
Best practices for large oracle apps r12 implementations apps14
DBA 3 year Interview Questions
z/OS SMPE Software Control PART 1 & PART2.pptx
Ibm db2 interview questions and answers
Resource Access Control Facility (RACF) in Mainframes
Tuning Autovacuum in Postgresql
Oracle Database SQL Tuning Concept
PostgreSQL and RAM usage
TFA Collector - what can one do with it
しばちょう先生が語る!オラクルデータベースの進化の歴史と最新技術動向#3
Optimizing InfluxDB Performance in the Real World by Dean Sheehan, Senior Dir...
Security of Oracle EBS - How I can Protect my System (UKOUG APPS 18 edition)
ICE: The ultimate way of beating NAT in SIP
Enable GoldenGate Monitoring with OEM 12c/JAgent
Oracle RAC 12c Practical Performance Management and Tuning OOW13 [CON8825]
RACF - The Basics (v1.2)
MAA for Oracle Database, Exadata and the Cloud
Db2 for z os trends
Oracle zdm Migrate Amazon RDS Oracle to Oracle Autonomous 2021 Kamalesh Ramas...
Ad

Similar to Sangam 19 - Analytic SQL (20)

PPTX
Analytic SQL Sep 2013
PPTX
Analytic functions in Oracle SQL - BIWA 2017
PDF
KScope19 - SQL Features
PDF
ANSI vs Oracle language
PDF
ILOUG 2019 - SQL features for Developers
PPTX
The Five Best Things To Happen To SQL
PPTX
Sangam 18 - Great Applications with Great SQL
PPTX
Perth APAC Groundbreakers tour - SQL Techniques
PDF
Pattern Matching with SQL - APEX World Rotterdam 2019
PDF
Latin America Tour 2019 - pattern matching
PDF
database application using SQL DML statements: Insert, Select, Update, Delet...
PDF
SQL for Data Professionals (Beginner)
PDF
DBMS Lab
DOCX
It6312 dbms lab-ex2
PPTX
Wellington APAC Groundbreakers tour - SQL Pattern Matching
PPTX
Complex Queries using MYSQL00123211.pptx
DOCX
Mysql and html
DOCX
1- Return the names- IDS- and average salary of the top 10 employees w.docx
PDF
Apurv Gupta, BCA ,Final year , Dezyne E'cole College
TXT
4sem dbms(1)
Analytic SQL Sep 2013
Analytic functions in Oracle SQL - BIWA 2017
KScope19 - SQL Features
ANSI vs Oracle language
ILOUG 2019 - SQL features for Developers
The Five Best Things To Happen To SQL
Sangam 18 - Great Applications with Great SQL
Perth APAC Groundbreakers tour - SQL Techniques
Pattern Matching with SQL - APEX World Rotterdam 2019
Latin America Tour 2019 - pattern matching
database application using SQL DML statements: Insert, Select, Update, Delet...
SQL for Data Professionals (Beginner)
DBMS Lab
It6312 dbms lab-ex2
Wellington APAC Groundbreakers tour - SQL Pattern Matching
Complex Queries using MYSQL00123211.pptx
Mysql and html
1- Return the names- IDS- and average salary of the top 10 employees w.docx
Apurv Gupta, BCA ,Final year , Dezyne E'cole College
4sem dbms(1)
Ad

More from Connor McDonald (20)

PDF
Flashback ITOUG
PDF
Sangam 19 - PLSQL still the coolest
PDF
Sangam 19 - Successful Applications on Autonomous
PDF
Sangam 2019 - The Latest Features
PDF
UKOUG 2019 - SQL features
PDF
APEX tour 2019 - successful development with autonomous
PDF
APAC Groundbreakers 2019 - Perth/Melbourne
PDF
OOW19 - Flashback, not just for DBAs
PDF
OOW19 - Read consistency
PDF
OOW19 - Slower and less secure applications
PDF
OOW19 - Killing database sessions
PDF
OOW19 - Ten Amazing SQL features
PDF
Latin America Tour 2019 - 18c and 19c featues
PDF
Latin America tour 2019 - Flashback
PDF
Latin America Tour 2019 - 10 great sql features
PDF
Latin America Tour 2019 - slow data and sql processing
PDF
OG Yatra - upgrading to the new 12c+ optimizer
PDF
OG Yatra - 25 years of hints and tips
PDF
OG Yatra - Flashback, not just for developers
PDF
Kscope19 - Flashback: Good for Developers as well as DBAs
Flashback ITOUG
Sangam 19 - PLSQL still the coolest
Sangam 19 - Successful Applications on Autonomous
Sangam 2019 - The Latest Features
UKOUG 2019 - SQL features
APEX tour 2019 - successful development with autonomous
APAC Groundbreakers 2019 - Perth/Melbourne
OOW19 - Flashback, not just for DBAs
OOW19 - Read consistency
OOW19 - Slower and less secure applications
OOW19 - Killing database sessions
OOW19 - Ten Amazing SQL features
Latin America Tour 2019 - 18c and 19c featues
Latin America tour 2019 - Flashback
Latin America Tour 2019 - 10 great sql features
Latin America Tour 2019 - slow data and sql processing
OG Yatra - upgrading to the new 12c+ optimizer
OG Yatra - 25 years of hints and tips
OG Yatra - Flashback, not just for developers
Kscope19 - Flashback: Good for Developers as well as DBAs

Recently uploaded (20)

PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Approach and Philosophy of On baking technology
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Encapsulation theory and applications.pdf
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Big Data Technologies - Introduction.pptx
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
Cloud computing and distributed systems.
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
KodekX | Application Modernization Development
PPTX
MYSQL Presentation for SQL database connectivity
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Dropbox Q2 2025 Financial Results & Investor Presentation
Network Security Unit 5.pdf for BCA BBA.
Per capita expenditure prediction using model stacking based on satellite ima...
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Approach and Philosophy of On baking technology
Building Integrated photovoltaic BIPV_UPV.pdf
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Encapsulation theory and applications.pdf
Spectral efficient network and resource selection model in 5G networks
The Rise and Fall of 3GPP – Time for a Sabbatical?
Big Data Technologies - Introduction.pptx
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
20250228 LYD VKU AI Blended-Learning.pptx
Cloud computing and distributed systems.
Reach Out and Touch Someone: Haptics and Empathic Computing
NewMind AI Weekly Chronicles - August'25 Week I
“AI and Expert System Decision Support & Business Intelligence Systems”
KodekX | Application Modernization Development
MYSQL Presentation for SQL database connectivity

Sangam 19 - Analytic SQL

  • 2. The power of SQL analytics Connor McDonald Database Advocate Copyright © 2019 Oracle and/or its affiliates.
  • 3. 3 3
  • 4. 4 4
  • 5. 5 Me youtube bit.ly/youtube-connor blog connor-mcdonald.com twitter @connor_mc_d 400+ posts mainly on database & development 250 technical videos, new uploads every week rants and raves on tech and the world :-)
  • 6. 6 etc... facebook bit.ly/facebook-connor linkedin bit.ly/linkedin-connor instagram bit.ly/instagram-connor slideshare bit.ly/slideshare-connor
  • 7. 7 the beauty of analytics
  • 9. 9 <function> ( <arg>,<arg>,… ) OVER ( <partition clause> <sorting clause> <windowing clause> )
  • 10. 10 <function> ( <arg>,<arg>,… ) OVER | KEEP ( <partition clause> <sorting clause> <windowing clause> )
  • 15. SQL> select empno, ename, job, hiredate, sal 2 from emp 3 order by sal; EMPNO ENAME JOB HIREDATE SAL ---------- ---------- --------- --------- ---------- 7369 SMITH CLERK 17-DEC-80 800 7900 JAMES CLERK 03-DEC-81 950 7876 ADAMS CLERK 12-JAN-83 1100 7521 WARD SALESMAN 22-FEB-81 1250 7654 MARTIN SALESMAN 28-SEP-81 1250 7934 MILLER CLERK 23-JAN-82 1300 7844 TURNER SALESMAN 08-SEP-81 1500 7499 ALLEN SALESMAN 20-FEB-81 1600 7782 CLARK MANAGER 09-JUN-81 2450 7698 BLAKE MANAGER 01-MAY-81 2850 7566 JONES MANAGER 02-APR-81 2975 7902 FORD ANALYST 03-DEC-81 3000 7788 SCOTT ANALYST 09-DEC-82 3000 7839 KING PRESIDENT 17-NOV-81 5000
  • 16. 16 "Show me the hiring sequence"
  • 17. EMPNO ENAME JOB HIREDATE SAL HIRE_SEQ ---------- ---------- --------- --------- ---------- ---------- 7369 SMITH CLERK 17-DEC-80 800 1 7900 JAMES CLERK 03-DEC-81 950 10 7876 ADAMS CLERK 12-JAN-83 1100 14 7521 WARD SALESMAN 22-FEB-81 1250 3 7654 MARTIN SALESMAN 28-SEP-81 1250 8 7934 MILLER CLERK 23-JAN-82 1300 12 7844 TURNER SALESMAN 08-SEP-81 1500 7 7499 ALLEN SALESMAN 20-FEB-81 1600 2 7782 CLARK MANAGER 09-JUN-81 2450 6 7698 BLAKE MANAGER 01-MAY-81 2850 5 7566 JONES MANAGER 02-APR-81 2975 4 7902 FORD ANALYST 03-DEC-81 3000 10 7788 SCOTT ANALYST 09-DEC-82 3000 13 7839 KING PRESIDENT 17-NOV-81 5000 9 SMITH was hired "first" ADAMS was hired “last"
  • 19. SQL> select e.empno, e.ename, e.job, 2 e.hiredate, e.sal, x.seq 3 from emp e, 4 ( select e2.empno, count(*) seq 5 from emp e1, emp e2 6 where e1.hiredate <= e2.hiredate 7 group by e2.empno 8 ) x 9 where e.empno = x.empno 10 order by sal;
  • 20. ------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | ------------------------------------------------------ | 0 | SELECT STATEMENT | | 10 | 1390 | | 1 | SORT GROUP BY | | 10 | 1390 | |* 2 | HASH JOIN | | 10 | 1390 | | 3 | MERGE JOIN | | 10 | 310 | | 4 | SORT JOIN | | 14 | 126 | | 5 | TABLE ACCESS FULL| EMP | 14 | 126 | |* 6 | SORT JOIN | | 14 | 308 | | 7 | TABLE ACCESS FULL| EMP | 14 | 308 | | 8 | TABLE ACCESS FULL | EMP | 14 | 1512 | ------------------------------------------------------
  • 21. SQL> select empno, ename, job, hiredate, sal, 2 rank() OVER (order by hiredate) as hire_seq 3 from emp 4 order by sal; EMPNO ENAME JOB HIREDATE SAL HIRE_SEQ ---------- ---------- --------- --------- ---------- ---------- 7369 SMITH CLERK 17-DEC-80 800 1 7900 JAMES CLERK 03-DEC-81 950 10 7876 ADAMS CLERK 12-JAN-83 1100 14 7521 WARD SALESMAN 22-FEB-81 1250 3 7654 MARTIN SALESMAN 28-SEP-81 1250 8 7934 MILLER CLERK 23-JAN-82 1300 12 7844 TURNER SALESMAN 08-SEP-81 1500 7 7499 ALLEN SALESMAN 20-FEB-81 1600 2 7782 CLARK MANAGER 09-JUN-81 2450 6 7698 BLAKE MANAGER 01-MAY-81 2850 5 7566 JONES MANAGER 02-APR-81 2975 4 7902 FORD ANALYST 03-DEC-81 3000 10 7788 SCOTT ANALYST 09-DEC-82 3000 13 7839 KING PRESIDENT 17-NOV-81 5000 9
  • 22. rank() OVER ( order by hire_date) as hire_seq function sorting clause
  • 24. RANK 1, 2, 3, 3, 5, ... functions for ranking
  • 25. RANK 1, 2, 3, 3, 5, ... DENSE_RANK 1, 2, 3, 3, 4, ... functions for ranking
  • 26. functions for ranking RANK 1, 2, 3, 3, 5, ... DENSE_RANK 1, 2, 3, 3, 4, ... CUME_DIST SQL> select ename, sal, 2 100*cume_dist() over ( order by sal ) as pct 3 from emp 4 order by sal; ENAME SAL PCT ---------- ---------- ------- SMITH 800 7.14 JAMES 950 14.29 ADAMS 1100 21.43 WARD 1250 35.71 MARTIN 1250 35.71 MILLER 1300 42.86 TURNER 1500 50.00 ALLEN 1600 57.14 CLARK 2450 64.29 BLAKE 2850 71.43 JONES 2975 78.57 FORD 3000 92.86 SCOTT 3000 92.86 KING 5000 100.00
  • 27. functions for ranking RANK 1, 2, 3, 3, 5, ... DENSE_RANK 1, 2, 3, 3, 4, ... CUME_DIST PERCENT_RANK SQL> select ename, sal, 2 100*percent_rank() over ( order by sal ) pct 3 from emp 4 order by ename; ENAME SAL PCT ---------- ---------- ------- ADAMS 1100 15.38 ALLEN 1600 53.85 BLAKE 2850 69.23 CLARK 2450 61.54 FORD 3000 84.62 JAMES 950 7.69 JONES 2975 76.92 KING 5000 100.00 MARTIN 1250 23.08 MILLER 1300 38.46 SCOTT 3000 84.62 SMITH 800 .00 TURNER 1500 46.15 WARD 1250 23.08
  • 28. functions for ranking RANK 1, 2, 3, 3, 5, ... DENSE_RANK 1, 2, 3, 3, 4, ... CUME_DIST PERCENT_RANK NTILE SQL> select ename, sal, 2 ntile(4) over ( order by sal ) as quartile 3 from emp 4 order by ename; ENAME SAL QUARTILE ---------- ---------- ---------- ADAMS 1100 1 ALLEN 1600 2 BLAKE 2850 3 CLARK 2450 3 FORD 3000 4 JAMES 950 1 JONES 2975 3 KING 5000 4 MARTIN 1250 2 MILLER 1300 2 SCOTT 3000 4 SMITH 800 1 TURNER 1500 2 WARD 1250 1
  • 29. RANK 1, 2, 3, 3, 5, ... DENSE_RANK 1, 2, 3, 3, 4, ... CUME_DIST PERCENT_RANK NTILE ROW_NUMBER 1, 2, 3, 4, 5, ... functions for ranking
  • 33. SQL> select deptno, empno, ename, job, sal 2 from emp 3 order by deptno, empno; DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7369 SMITH CLERK 800 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 30 7499 ALLEN SALESMAN 1600 30 7521 WARD SALESMAN 1250 30 7654 MARTIN SALESMAN 1250 30 7698 BLAKE MANAGER 2850 30 7844 TURNER SALESMAN 1500 30 7900 JAMES CLERK 950
  • 35. DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7369 SMITH CLERK 800 30 7499 ALLEN SALESMAN 1600 30 7698 BLAKE MANAGER 2850 30 7900 JAMES CLERK 950 30 7654 MARTIN SALESMAN 1250 30 7844 TURNER SALESMAN 1500 30 7521 WARD SALESMAN 1250 RUNNING_TOTAL ------------- 2450 7450 8750 1100 4100 7075 10075 10875 1600 4450 5400 6650 8150 9400 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, ename;
  • 36. DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7369 SMITH CLERK 800 30 7499 ALLEN SALESMAN 1600 30 7698 BLAKE MANAGER 2850 30 7900 JAMES CLERK 950 30 7654 MARTIN SALESMAN 1250 30 7844 TURNER SALESMAN 1500 30 7521 WARD SALESMAN 1250 RUNNING_TOTAL ------------- 2450 7450 8750 1100 4100 7075 10075 10875 1600 4450 5400 6650 8150 9400 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, ename;
  • 37. DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7369 SMITH CLERK 800 30 7499 ALLEN SALESMAN 1600 30 7698 BLAKE MANAGER 2850 30 7900 JAMES CLERK 950 30 7654 MARTIN SALESMAN 1250 30 7844 TURNER SALESMAN 1500 30 7521 WARD SALESMAN 1250 RUNNING_TOTAL ------------- 2450 7450 8750 1100 4100 7075 10075 10875 1600 4450 5400 6650 8150 9400 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, ename;
  • 38. DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7369 SMITH CLERK 800 30 7499 ALLEN SALESMAN 1600 30 7698 BLAKE MANAGER 2850 30 7900 JAMES CLERK 950 30 7654 MARTIN SALESMAN 1250 30 7844 TURNER SALESMAN 1500 30 7521 WARD SALESMAN 1250 RUNNING_TOTAL ------------- 2450 7450 8750 1100 4100 7075 10075 10875 1600 4450 5400 6650 8150 9400 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, ename;
  • 39. DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7369 SMITH CLERK 800 30 7499 ALLEN SALESMAN 1600 30 7698 BLAKE MANAGER 2850 30 7900 JAMES CLERK 950 30 7654 MARTIN SALESMAN 1250 30 7844 TURNER SALESMAN 1500 30 7521 WARD SALESMAN 1250 RUNNING_TOTAL ------------- 2450 7450 8750 1100 4100 7075 10075 10875 1600 4450 5400 6650 8150 9400 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, ename;
  • 40. sum(sal) OVER ( partition by deptno order by ename) as running_total function sorting clause partition clause
  • 42. DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7369 SMITH CLERK 800 30 7499 ALLEN SALESMAN 1600 30 7698 BLAKE MANAGER 2850 30 7900 JAMES CLERK 950 30 7654 MARTIN SALESMAN 1250 30 7844 TURNER SALESMAN 1500 30 7521 WARD SALESMAN 1250 RUNNING_TOTAL ------------- 2450 7450 8750 1100 4100 7075 10075 10875 1600 4450 5400 6650 8150 9400 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, ename;
  • 43. SQL> select deptno, empno, ename, job, sal 2 from emp 3 order by deptno, hiredate; DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7369 SMITH CLERK 800 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 30 7499 ALLEN SALESMAN 1600 30 7521 WARD SALESMAN 1250 30 7654 MARTIN SALESMAN 1250 30 7698 BLAKE MANAGER 2850 30 7844 TURNER SALESMAN 1500 30 7900 JAMES CLERK 950 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, hiredate RUNNING_TOTAL ------------- 2450 7450 8750 10875 7075 10075 1100 4100 1600 9400 6650 4450 8150 5400
  • 45. SQL> select deptno, job, ename, sal, 2 sum(sal) over () total_sal, 3 sum(sal) over 4 ( partition by deptno) sal_by_dept, 5 sum(sal) over 6 ( partition by deptno, job) sal_by_dept_job 7 from emp 8 order by deptno, job; DEPTNO JOB ENAME SAL ---------- --------- ---------- ---------- 10 CLERK MILLER 1300 10 MANAGER CLARK 2450 10 PRESIDENT KING 5000 20 ANALYST SCOTT 3000 20 ANALYST FORD 3000 20 CLERK ADAMS 1100 20 CLERK SMITH 800 20 MANAGER JONES 2975 30 CLERK JAMES 950 30 MANAGER BLAKE 2850 30 SALESMAN TURNER 1500 30 SALESMAN MARTIN 1250 30 SALESMAN WARD 1250 30 SALESMAN ALLEN 1600 TOTAL_SAL ---------- 29025 29025 29025 29025 29025 29025 29025 29025 29025 29025 29025 29025 29025 29025 SAL_BY_DEPT ----------- 8750 8750 8750 10875 10875 10875 10875 10875 9400 9400 9400 9400 9400 9400 SAL_BY_DEPT_JOB --------------- 1300 2450 5000 6000 6000 1900 1900 2975 950 2850 5600 5600 5600 5600
  • 46. and a whole lot more... COLLECT CORR COVAR_POP COVAR_SAMP GROUP_ID GROUPING GROUPING_ID MEDIAN PERCENTILE_CONT PERCENTILE_DISC REGR_ ... STATS_BINOMIAL_TEST STATS_KS_TEST STATS_MODE STATS_MW_TEST STATS_ONE_WAY_ANOVA STATS_F_TEST STATS_CROSSTAB STATS_T_TEST_... STATS_WSR_TEST STDDEV STDDEV_POP STDDEV_SAMP VAR_POP VAR_SAMP VARIANCE
  • 48. 48 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( ... ), 3 max(hiredate) over ( ... ), 4 stddev(commission) over ( .... ) ... ... ... 25 from emp
  • 49. 49 a lot of work
  • 50. 50 and a little surprise...
  • 51. 51 SQL> select deptno, empno, ename, job, sal 2 from emp 3 order by deptno, empno; ---------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| ---------------------------------------------------------------- | 0 | SELECT STATEMENT | | 12 | 1044 | 4 (25)| | 1 | SORT ORDER BY | | 12 | 1044 | 4 (25)| | 2 | TABLE ACCESS FULL| EMP | 12 | 1044 | 3 (0)| ----------------------------------------------------------------
  • 52. 52 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp 6 order by deptno, empno ---------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| ---------------------------------------------------------------- | 0 | SELECT STATEMENT | | 12 | 468 | 3 (0)| | 1 | WINDOW SORT | | 12 | 468 | 3 (0)| | 2 | TABLE ACCESS FULL| EMP | 12 | 468 | 3 (0)| ----------------------------------------------------------------
  • 59. 59 SQL> select deptno, sum(sal) 2 from emp 3 group by deptno; DEPTNO SUM(SAL) ---------- ---------- 10 8750 20 10875 30 9400
  • 60. 60 SQL> select ename, deptno, 2 sum(sal) over 3 ( partition by deptno) as deptsal 4 from emp 5 order by deptno; ENAME DEPTNO DEPTSAL ---------- ---------- ---------- CLARK 10 8750 KING 10 8750 MILLER 10 8750 JONES 20 10875 FORD 20 10875 ADAMS 20 10875 SMITH 20 10875 SCOTT 20 10875 WARD 30 9400 TURNER 30 9400 ALLEN 30 9400 JAMES 30 9400 BLAKE 30 9400 MARTIN 30 9400 still 14 rows !!!
  • 64. 64 SQL> select ename, deptno, 2 sum(sal) over ( partition by deptno) as deptsal 3 from emp 4 order by deptno; ENAME DEPTNO DEPTSAL ---------- ---------- ---------- CLARK 10 8750 KING 10 8750 MILLER 10 8750 JONES 20 10875 FORD 20 10875 ADAMS 20 10875 SMITH 20 10875 SCOTT 20 10875 WARD 30 9400 TURNER 30 9400 ALLEN 30 9400 JAMES 30 9400 BLAKE 30 9400 MARTIN 30 9400 same for each row in partition
  • 66. <function> ( <arg>,<arg>,… ) OVER ( <partition clause> <sorting clause> <windowing clause> ) defines how broadly the aggregating function applies
  • 67. 67 "show me a salary running total"
  • 68. SQL> select 2 empno, ename, sal, 3 sum(sal) 4 over ( order by empno 5 rows between unbounded preceding and current row ) as cumtot 6 from emp 7 order by empno; EMPNO ENAME SAL CUMTOT ---------- ---------- ---------- ---------- 7369 SMITH 800 800 7499 ALLEN 1600 2400 7521 WARD 1250 3650 7566 JONES 2975 6625 7654 MARTIN 1250 7875 7698 BLAKE 2850 10725 7782 CLARK 2450 13175 7788 SCOTT 3000 16175 7839 KING 5000 21175 7844 TURNER 1500 22675 7876 ADAMS 1100 23775 7900 JAMES 950 24725 7902 FORD 3000 27725 7934 MILLER 1300 29025
  • 69. SQL> select 2 empno, ename, sal, 3 sum(sal) 4 over ( order by empno 5 rows between unbounded preceding and current row ) as cumtot 6 from emp 7 order by empno; EMPNO ENAME SAL CUMTOT ---------- ---------- ---------- ---------- 7369 SMITH 800 800 7499 ALLEN 1600 2400 7521 WARD 1250 3650 7566 JONES 2975 6625 7654 MARTIN 1250 7875 7698 BLAKE 2850 10725 7782 CLARK 2450 13175 7788 SCOTT 3000 16175 7839 KING 5000 21175 7844 TURNER 1500 22675 7876 ADAMS 1100 23775 7900 JAMES 950 24725 7902 FORD 3000 27725 7934 MILLER 1300 29025
  • 70. SQL> select 2 empno, ename, sal, 3 sum(sal) 4 over ( order by empno 5 rows between unbounded preceding and current row ) as cumtot 6 from emp 7 order by empno; EMPNO ENAME SAL CUMTOT ---------- ---------- ---------- ---------- 7369 SMITH 800 800 7499 ALLEN 1600 2400 7521 WARD 1250 3650 7566 JONES 2975 6625 7654 MARTIN 1250 7875 7698 BLAKE 2850 10725 7782 CLARK 2450 13175 7788 SCOTT 3000 16175 7839 KING 5000 21175 7844 TURNER 1500 22675 7876 ADAMS 1100 23775 7900 JAMES 950 24725 7902 FORD 3000 27725 7934 MILLER 1300 29025
  • 71. SQL> select 2 empno, ename, sal, 3 sum(sal) 4 over ( order by empno 5 rows between unbounded preceding and current row ) as cumtot 6 from emp 7 order by empno; EMPNO ENAME SAL CUMTOT ---------- ---------- ---------- ---------- 7369 SMITH 800 800 7499 ALLEN 1600 2400 7521 WARD 1250 3650 7566 JONES 2975 6625 7654 MARTIN 1250 7875 7698 BLAKE 2850 10725 7782 CLARK 2450 13175 7788 SCOTT 3000 16175 7839 KING 5000 21175 7844 TURNER 1500 22675 7876 ADAMS 1100 23775 7900 JAMES 950 24725 7902 FORD 3000 27725 7934 MILLER 1300 29025
  • 72. 72 "give me the sum across 3 rows, ie, one before and one after"
  • 73. SQL> select deptno, ename, hiredate, sal, 2 sum(sal) over ( 3 partition by deptno 4 order by hiredate 5 rows between 1 preceding and 1 following) as x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- ---------- 10 CLARK 09-JUN-81 2450 7450 10 KING 17-NOV-81 5000 8750 10 MILLER 23-JAN-82 1300 6300 20 SMITH 17-DEC-80 800 3775 20 JONES 02-APR-81 2975 6775 20 FORD 03-DEC-81 3000 8975 20 SCOTT 09-DEC-82 3000 7100 20 ADAMS 12-JAN-83 1100 4100 30 ALLEN 20-FEB-81 1600 2850 30 WARD 22-FEB-81 1250 5700 30 BLAKE 01-MAY-81 2850 5600 30 TURNER 08-SEP-81 1500 5600 30 MARTIN 28-SEP-81 1250 3700 30 JAMES 03-DEC-81 950 2200
  • 74. SQL> select deptno, ename, hiredate, sal, 2 sum(sal) over ( 3 partition by deptno 4 order by hiredate 5 rows between 1 preceding and 1 following) as x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- ---------- 10 CLARK 09-JUN-81 2450 7450 10 KING 17-NOV-81 5000 8750 10 MILLER 23-JAN-82 1300 6300 20 SMITH 17-DEC-80 800 3775 20 JONES 02-APR-81 2975 6775 20 FORD 03-DEC-81 3000 8975 20 SCOTT 09-DEC-82 3000 7100 20 ADAMS 12-JAN-83 1100 4100 30 ALLEN 20-FEB-81 1600 2850 30 WARD 22-FEB-81 1250 5700 30 BLAKE 01-MAY-81 2850 5600 30 TURNER 08-SEP-81 1500 5600 30 MARTIN 28-SEP-81 1250 3700 30 JAMES 03-DEC-81 950 2200
  • 75. SQL> select deptno, ename, hiredate, sal, 2 sum(sal) over ( 3 partition by deptno 4 order by hiredate 5 rows between 1 preceding and 1 following) as x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- ---------- 10 CLARK 09-JUN-81 2450 7450 10 KING 17-NOV-81 5000 8750 10 MILLER 23-JAN-82 1300 6300 20 SMITH 17-DEC-80 800 3775 20 JONES 02-APR-81 2975 6775 20 FORD 03-DEC-81 3000 8975 20 SCOTT 09-DEC-82 3000 7100 20 ADAMS 12-JAN-83 1100 4100 30 ALLEN 20-FEB-81 1600 2850 30 WARD 22-FEB-81 1250 5700 30 BLAKE 01-MAY-81 2850 5600 30 TURNER 08-SEP-81 1500 5600 30 MARTIN 28-SEP-81 1250 3700 30 JAMES 03-DEC-81 950 2200
  • 76. SQL> select deptno, ename, hiredate, sal, 2 sum(sal) over ( 3 partition by deptno 4 order by hiredate 5 rows between 1 preceding and 1 following) as x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- ---------- 10 CLARK 09-JUN-81 2450 7450 10 KING 17-NOV-81 5000 8750 10 MILLER 23-JAN-82 1300 6300 20 SMITH 17-DEC-80 800 3775 20 JONES 02-APR-81 2975 6775 20 FORD 03-DEC-81 3000 8975 20 SCOTT 09-DEC-82 3000 7100 20 ADAMS 12-JAN-83 1100 4100 30 ALLEN 20-FEB-81 1600 2850 30 WARD 22-FEB-81 1250 5700 30 BLAKE 01-MAY-81 2850 5600 30 TURNER 08-SEP-81 1500 5600 30 MARTIN 28-SEP-81 1250 3700 30 JAMES 03-DEC-81 950 2200
  • 77. 77 "I need a 6 month moving average"
  • 78. SQL> select deptno, ename, hiredate, sal, 2 avg(sal) over ( 3 partition by deptno 4 order by hiredate 5 range between interval '6' month preceding and current row ) x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- -------- 10 CLARK 09-JUN-81 2450 2450 10 KING 17-NOV-81 5000 3725 10 MILLER 23-JAN-82 1300 3150 20 SMITH 17-DEC-80 800 800 20 JONES 02-APR-81 2975 1888 20 FORD 03-DEC-81 3000 3000 20 SCOTT 09-DEC-82 3000 3000 20 ADAMS 12-JAN-83 1100 2050 30 ALLEN 20-FEB-81 1600 1600 30 WARD 22-FEB-81 1250 1425 30 BLAKE 01-MAY-81 2850 1900 30 TURNER 08-SEP-81 1500 2175 30 MARTIN 28-SEP-81 1250 1867 30 JAMES 03-DEC-81 950 1233
  • 79. SQL> select deptno, ename, hiredate, sal, 2 avg(sal) over ( 3 partition by deptno 4 order by hiredate 5 range between interval '6' month preceding and current row ) x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- -------- 10 CLARK 09-JUN-81 2450 2450 10 KING 17-NOV-81 5000 3725 10 MILLER 23-JAN-82 1300 3150 20 SMITH 17-DEC-80 800 800 20 JONES 02-APR-81 2975 1888 20 FORD 03-DEC-81 3000 3000 20 SCOTT 09-DEC-82 3000 3000 20 ADAMS 12-JAN-83 1100 2050 30 ALLEN 20-FEB-81 1600 1600 30 WARD 22-FEB-81 1250 1425 30 BLAKE 01-MAY-81 2850 1900 30 TURNER 08-SEP-81 1500 2175 30 MARTIN 28-SEP-81 1250 1867 30 JAMES 03-DEC-81 950 1233
  • 80. SQL> select deptno, ename, hiredate, sal, 2 avg(sal) over ( 3 partition by deptno 4 order by hiredate 5 range between interval '6' month preceding and current row ) x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- -------- 10 CLARK 09-JUN-81 2450 2450 10 KING 17-NOV-81 5000 3725 10 MILLER 23-JAN-82 1300 3150 20 SMITH 17-DEC-80 800 800 20 JONES 02-APR-81 2975 1888 20 FORD 03-DEC-81 3000 3000 20 SCOTT 09-DEC-82 3000 3000 20 ADAMS 12-JAN-83 1100 2050 30 ALLEN 20-FEB-81 1600 1600 30 WARD 22-FEB-81 1250 1425 30 BLAKE 01-MAY-81 2850 1900 30 TURNER 08-SEP-81 1500 2175 30 MARTIN 28-SEP-81 1250 1867 30 JAMES 03-DEC-81 950 1233
  • 81. SQL> select deptno, ename, hiredate, sal, 2 avg(sal) over ( 3 partition by deptno 4 order by hiredate 5 range between interval '6' month preceding and current row ) x 6 from emp 7 order by deptno, hiredate; DEPTNO ENAME HIREDATE SAL X ---------- ---------- --------- ---------- -------- 10 CLARK 09-JUN-81 2450 2450 10 KING 17-NOV-81 5000 3725 10 MILLER 23-JAN-82 1300 3150 20 SMITH 17-DEC-80 800 800 20 JONES 02-APR-81 2975 1888 20 FORD 03-DEC-81 3000 3000 20 SCOTT 09-DEC-82 3000 3000 20 ADAMS 12-JAN-83 1100 2050 30 ALLEN 20-FEB-81 1600 1600 30 WARD 22-FEB-81 1250 1425 30 BLAKE 01-MAY-81 2850 1900 30 TURNER 08-SEP-81 1500 2175 30 MARTIN 28-SEP-81 1250 1867 30 JAMES 03-DEC-81 950 1233
  • 82. 82 windows can be dynamic
  • 83. 83 "I need the sum sales from the previous week day "
  • 84. SQL> create or replace 2 function LAST_CLOSE(p_purchase_date date) 3 return number is 4 begin 5 return 6 case to_char(p_purchase_date,'DY') 7 when 'SUN' then 2 -- Fri,Sat 8 when 'MON' then 3 -- Fri,Sat,Sun 9 else 1 10 end; 11 end; 12 / Function created. SQL> select 2 prod_id, cust_id, 3 sum(amount_sold) 4 over ( order by purchase_date 5 range between LAST_CLOSE(purchase_date) preceding) as bus_tot 6 from sales 7 /
  • 87. 87 "compare each salary with first person hired across entire organisation and within each department"
  • 88. SQL> select deptno, hiredate, empno, ename, sal, 2 first_value(sal) over ( order by hiredate 3 range unbounded preceding ) lo_sal, 4 first_value(sal) over ( partition by deptno 5 order by hiredate 6 range unbounded preceding) lo_dept_sal 7 from emp 8 order by deptno, hiredate; DEPTNO HIREDATE EMPNO ENAME SAL ---------- --------- ---------- ---------- ---------- 10 09-JUN-81 7782 CLARK 2450 10 17-NOV-81 7839 KING 5000 10 23-JAN-82 7934 MILLER 1300 20 17-DEC-80 7369 SMITH 800 20 02-APR-81 7566 JONES 2975 20 03-DEC-81 7902 FORD 3000 20 09-DEC-82 7788 SCOTT 3000 20 12-JAN-83 7876 ADAMS 1100 30 20-FEB-81 7499 ALLEN 1600 30 22-FEB-81 7521 WARD 1250 30 01-MAY-81 7698 BLAKE 2850 30 08-SEP-81 7844 TURNER 1500 30 28-SEP-81 7654 MARTIN 1250 30 03-DEC-81 7900 JAMES 950 LO_SAL ---------- 800 800 800 800 800 800 800 800 800 800 800 800 800 800 LO_DEPT_SAL ----------- 2450 2450 2450 800 800 800 800 800 1600 1600 1600 1600 1600 1600
  • 91. 91 "compare each salary with second hired person across entire organisation and within each department"
  • 92. SQL> select deptno, hiredate, empno, ename, sal, 2 100 * sal / nth_value(sal,2) over ( order by hiredate 3 range unbounded preceding ) sal_pct, 4 100 * sal / nth_value(sal,2) over ( partition by deptno 5 order by hiredate 6 range unbounded preceding) dept_sal_pct 7 from emp 8 order by deptno, hiredate; DEPTNO HIREDATE EMPNO ENAME SAL ---------- --------- ---------- ---------- ---------- 10 09-JUN-81 7782 CLARK 2450 10 17-NOV-81 7839 KING 5000 10 23-JAN-82 7934 MILLER 1300 20 17-DEC-80 7369 SMITH 800 20 02-APR-81 7566 JONES 2975 20 03-DEC-81 7902 FORD 3000 20 09-DEC-82 7788 SCOTT 3000 20 12-JAN-83 7876 ADAMS 1100 30 20-FEB-81 7499 ALLEN 1600 30 22-FEB-81 7521 WARD 1250 30 01-MAY-81 7698 BLAKE 2850 30 08-SEP-81 7844 TURNER 1500 30 28-SEP-81 7654 MARTIN 1250 30 03-DEC-81 7900 JAMES 950 SAL_PCT ------- 153.13 312.50 81.25 185.94 187.50 187.50 68.75 100.00 78.13 178.13 93.75 78.13 59.38 DEPT_SAL_PCT ------------ 100.00 26.00 100.00 100.84 100.84 36.97 100.00 228.00 120.00 100.00 76.00
  • 94. SQL> select empno, ename, sal, deptno 2 from emp 3 order by sal; EMPNO ENAME SAL DEPTNO ---------- ---------- ---------- ---------- 7369 SMITH 800 10 7900 JAMES 950 7876 ADAMS 1100 7521 WARD 1250 20 7654 MARTIN 1250 7934 MILLER 1300 7844 TURNER 1500 7499 ALLEN 1600 30 7782 CLARK 2450 7698 BLAKE 2850 7566 JONES 2975 7788 SCOTT 3000 7902 FORD 3000 7839 KING 5000 40
  • 95. SQL> select empno, ename, sal, deptno, 2 last_value(deptno IGNORE NULLS) 3 over (order by sal) as last_dept 4 from emp 5 order by sal EMPNO ENAME SAL DEPTNO ---------- ---------- ---------- ---------- 7369 SMITH 800 10 7900 JAMES 950 7876 ADAMS 1100 7521 WARD 1250 20 7654 MARTIN 1250 7934 MILLER 1300 7844 TURNER 1500 7499 ALLEN 1600 30 7782 CLARK 2450 7698 BLAKE 2850 7566 JONES 2975 7788 SCOTT 3000 7902 FORD 3000 7839 KING 5000 40 LAST_DEPT ---------- 10 10 10 20 20 20 20 30 30 30 30 30 30 40
  • 96. SQL> select last_dept, count(*) 2 from 3 ( select 4 last_value(deptno ignore nulls) 5 over (order by sal) as last_dept 6 from emp2 7 ) 8 group by last_dept; LAST_DEPT COUNT(*) ---------- ---------- 30 6 20 4 40 1 10 3
  • 99. SQL> select ename, deptno, 2 sum(sal) over ( partition by deptno ) as deptsal 3 from emp 4 order by deptno; ENAME DEPTNO DEPTSAL ---------- ---------- ---------- CLARK 10 8750 KING 10 8750 MILLER 10 8750 JONES 20 10875 FORD 20 10875 ADAMS 20 10875 SMITH 20 10875 SCOTT 20 10875 WARD 30 9400 TURNER 30 9400 ALLEN 30 9400 JAMES 30 9400 BLAKE 30 9400 MARTIN 30 9400 reporting aggregate
  • 100. DEPTNO EMPNO ENAME JOB SAL ---------- ---------- ---------- --------- ---------- 10 7782 CLARK MANAGER 2450 10 7839 KING PRESIDENT 5000 10 7934 MILLER CLERK 1300 20 7876 ADAMS CLERK 1100 20 7902 FORD ANALYST 3000 20 7566 JONES MANAGER 2975 20 7788 SCOTT ANALYST 3000 20 7369 SMITH CLERK 800 30 7499 ALLEN SALESMAN 1600 30 7698 BLAKE MANAGER 2850 30 7900 JAMES CLERK 950 30 7654 MARTIN SALESMAN 1250 30 7844 TURNER SALESMAN 1500 30 7521 WARD SALESMAN 1250 RUNNING_TOTAL ------------- 2450 7450 8750 1100 4100 7075 10075 10875 1600 4450 5400 6650 8150 9400 SQL> select deptno, empno, ename, job, sal, 2 sum(sal) OVER ( 3 partition by deptno 4 order by ename) as running_total 5 from emp windowing aggregate
  • 101. <function> ( <arg>,<arg>,… ) OVER ( <partition clause> <sorting clause> <windowing clause> ) but I didn't specify one of these ?
  • 102. <function> ( <arg>,<arg>,… ) OVER ( <partition clause> <sorting clause> <windowing clause> ) THEN you get one of these automatically ! IF this is an aggregate function ... AND you have included an ORDER BY clause ... range between unbounded preceding and current row
  • 103. sum(sal) OVER ( partition by deptno ) function partition clause order by ename
  • 106. SQL> select 2 empno, ename, hiredate, sal, 3 lag(sal,1) 4 over ( order by hiredate ) prev_hire_sal 5 from emp 6 order by hiredate; EMPNO ENAME HIREDATE SAL ---------- ---------- --------- ---------- 7369 SMITH 17-DEC-80 800 7499 ALLEN 20-FEB-81 1600 7521 WARD 22-FEB-81 1250 7566 JONES 02-APR-81 2975 7698 BLAKE 01-MAY-81 2850 7782 CLARK 09-JUN-81 2450 7844 TURNER 08-SEP-81 1500 7654 MARTIN 28-SEP-81 1250 7839 KING 17-NOV-81 5000 7900 JAMES 03-DEC-81 950 7902 FORD 03-DEC-81 3000 7934 MILLER 23-JAN-82 1300 7788 SCOTT 09-DEC-82 3000 7876 ADAMS 12-JAN-83 1100 PREV_HIRE_SAL -------------- 800 1600 1250 2975 2850 2450 1500 1250 5000 950 3000 1300 3000
  • 109. SQL> select empno, ename, sal 2 from emp 3 order by empno; EMPNO ENAME SAL ---------- ---------- ---------- 7369 SMITH 800 7499 ALLEN 7521 WARD 7566 JONES 7654 MARTIN 1250 7698 BLAKE 7782 CLARK 7788 SCOTT 7839 KING 5000 7844 TURNER 7876 ADAMS 7900 JAMES 7902 FORD 7934 MILLER
  • 110. SQL> select empno, ename, sal, 2 lag(sal,1) 3 over ( order by empno) as prev_sal 4 from emp 5 order by empno; EMPNO ENAME SAL PREV_SAL ---------- ---------- ---------- ---------- 7369 SMITH 800 7499 ALLEN 800 7521 WARD 7566 JONES 7654 MARTIN 1250 7698 BLAKE 1250 7782 CLARK 7788 SCOTT 7839 KING 5000 7844 TURNER 5000 7876 ADAMS 7900 JAMES 7902 FORD 7934 MILLER
  • 111. SQL> select empno, ename, sal, 2 lag(sal,1) ignore nulls 3 over ( order by empno) as prev_sal 4 from emp 5 order by empno; EMPNO ENAME SAL ---------- ---------- ---------- 7369 SMITH 800 7499 ALLEN 7521 WARD 7566 JONES 7654 MARTIN 1250 7698 BLAKE 7782 CLARK 7788 SCOTT 7839 KING 5000 7844 TURNER 7876 ADAMS 7900 JAMES 7902 FORD 7934 MILLER PREV_SAL ---------- 800 800 800 800 1250 1250 1250 1250 5000 5000 5000 5000 5000
  • 113. 113 “imagination is more important than knowledge” - Albert Einstein
  • 117. SQL> select * from BAD_EMP; EMPNO ENAME JOB MGR HIREDATE SAL ---------- ---------- --------- ---------- --------- ---------- 7788 SCOTT ANALYST 7566 09-DEC-82 3000 7499 ALLEN SALESMAN 7698 20-FEB-81 1600 7369 SMITH CLERK 7902 17-DEC-80 800 7839 KING PRESIDENT 17-NOV-81 5000 7566 JONES MANAGER 7839 02-APR-81 2975 7876 ADAMS CLERK 7788 12-JAN-83 1100 7844 TURNER SALESMAN 7698 08-SEP-81 1500 7499 ALLEN SALESMAN 7698 20-FEB-81 1600 7369 SMITH CLERK 7902 17-DEC-80 800 7902 FORD ANALYST 7566 03-DEC-81 3000 7900 JAMES CLERK 7698 03-DEC-81 950 7521 WARD SALESMAN 7698 22-FEB-81 1250 7654 MARTIN SALESMAN 7698 28-SEP-81 1250 7934 MILLER CLERK 7782 23-JAN-82 1300 7698 BLAKE MANAGER 7839 01-MAY-81 2850 7782 CLARK MANAGER 7839 09-JUN-81 2450
  • 118. SQL> select * from BAD_EMP; EMPNO ENAME JOB MGR HIREDATE SAL ---------- ---------- --------- ---------- --------- ---------- 7788 SCOTT ANALYST 7566 09-DEC-82 3000 7499 ALLEN SALESMAN 7698 20-FEB-81 1600 7369 SMITH CLERK 7902 17-DEC-80 800 7839 KING PRESIDENT 17-NOV-81 5000 7566 JONES MANAGER 7839 02-APR-81 2975 7876 ADAMS CLERK 7788 12-JAN-83 1100 7844 TURNER SALESMAN 7698 08-SEP-81 1500 7499 ALLEN SALESMAN 7698 20-FEB-81 1600 7369 SMITH CLERK 7902 17-DEC-80 800 7902 FORD ANALYST 7566 03-DEC-81 3000 7900 JAMES CLERK 7698 03-DEC-81 950 7521 WARD SALESMAN 7698 22-FEB-81 1250 7654 MARTIN SALESMAN 7698 28-SEP-81 1250 7934 MILLER CLERK 7782 23-JAN-82 1300 7698 BLAKE MANAGER 7839 01-MAY-81 2850 7782 CLARK MANAGER 7839 09-JUN-81 2450
  • 119. SQL> select empno, rowid, 2 row_number() over 3 ( partition by empno order by rowid ) as r 4 from BAD_EMP 5 / EMPNO ROWID R ---------- ------------------ ---------- 7369 AAARXwAAEAAATlMAAA 1 7369 AAARXwAAEAAATlOAAA 2 7499 AAARXwAAEAAATlMAAB 1 7499 AAARXwAAEAAATlOAAB 2 7521 AAARXwAAEAAATlMAAC 1 7566 AAARXwAAEAAATlMAAD 1 7654 AAARXwAAEAAATlMAAE 1 7698 AAARXwAAEAAATlMAAF 1 7782 AAARXwAAEAAATlMAAG 1 7788 AAARXwAAEAAATlMAAH 1 7839 AAARXwAAEAAATlMAAI 1 7844 AAARXwAAEAAATlMAAJ 1 7876 AAARXwAAEAAATlMAAK 1 7900 AAARXwAAEAAATlMAAL 1 7902 AAARXwAAEAAATlMAAM 1 7934 AAARXwAAEAAATlMAAN 1
  • 120. SQL> delete from BAD_EMP 2 where ROWID in 3 ( select rowid 4 from 5 ( select rowid, 6 row_number() over 7 ( partition by empno 8 order by rowid) as r 9 from BAD_EMP 10 ) 11 where r > 1 12 ) 13 / 2 rows deleted.
  • 121. 121 “5 highest salaries from each department”
  • 122. SQL> select deptno, salary 2 from 3 ( select 4 deptno, 5 salary, 6 rank() over ( 7 partition by deptno 8 order by salary) top_5 9 from EMPLOYEES 10 ) 11 where top_5 <= 5
  • 124. 124 SQL> select X from T; X ---------- 2 3 4 7 8 12 13 15 16 17 19 20 2-4 7-8 12-13 15-17 19-20
  • 125. 125 SQL> select 2 x, 3 lag(x) over ( order by x) prev 4 from T ; X PREV ---------- ---------- 2 3 2 4 3 7 4 8 7 12 8 13 12 15 13 16 15 17 16 19 17 20 19
  • 126. 126 SQL> select 2 x, 3 lag(x) over ( order by x) prev 4 from T ; X PREV ---------- ---------- 2 3 2 4 3 7 4 8 7 12 8 13 12 15 13 16 15 17 16 19 17 20 19
  • 127. 127 SQL> select 2 x, 3 lag(x) over ( order by x) prev 4 from T ; X PREV ---------- ---------- 2 3 2 4 3 7 4 8 7 12 8 13 12 15 13 16 15 17 16 19 17 20 19
  • 128. 128 SQL> select 2 x, 3 lag(x) over ( order by x) prev 4 from T ; X PREV ---------- ---------- 2 3 2 4 3 7 4 8 7 12 8 13 12 15 13 16 15 17 16 19 17 20 19
  • 129. 129 SQL> select 2 x, 3 lag(x) over ( order by x) prev 4 from T ; X PREV ---------- ---------- 2 3 2 4 3 7 4 8 7 12 8 13 12 15 13 16 15 17 16 19 17 20 19
  • 130. 130 SQL> select 2 x, 3 case 4 when nvl(lag(x) over (order by x),x) != x-1 5 then x end loval 6 from t; X LOVAL ---------- ---------- 2 2 3 4 7 7 8 12 12 13 15 15 16 17 19 19 20
  • 131. 131 SQL> select 2 x, 3 case 4 when nvl(lag(x) over (order by x),x) != x-1 5 then x end loval 6 from t; X LOVAL ---------- ---------- 2 2 3 4 7 7 8 12 12 13 15 15 16 17 19 19 20
  • 132. 132 SQL> select 2 x, 3 case 4 when nvl(lag(x) over (order by x),x) != x-1 5 then x end loval 6 from t; X LOVAL ---------- ---------- 2 2 3 4 7 7 8 12 12 13 15 15 16 17 19 19 20
  • 133. 133 SQL> select 2 x, 3 case 4 when nvl(lag(x) over (order by x),x) != x-1 5 then x end loval 6 from t; X LOVAL ---------- ---------- 2 2 3 4 7 7 8 12 12 13 15 15 16 17 19 19 20
  • 134. 134 SQL> select x, max(loval) over (order by x) loval 2 from ( 3 select x, 4 case 5 when nvl(lag(x) over (order by x),x) != x-1 6 then x end loval 7 from t ); X LOVAL ---------- ---------- 2 2 3 2 4 2 7 7 8 7 12 12 13 12 15 15 16 15 17 15 19 19 20 19
  • 135. 135 SQL> select x, max(loval) over (order by x) loval 2 from ( 3 select x, 4 case 5 when nvl(lag(x) over (order by x),x) != x-1 6 then x end loval 7 from t ); X LOVAL ---------- ---------- 2 2 3 2 4 2 7 7 8 7 12 12 13 12 15 15 16 15 17 15 19 19 20 19
  • 136. 136 SQL> select min(x)||’-’||max(x) ranges from ( 2 select x,max(loval) over (order by x) loval 3 from ( 4 select x, 5 case 6 when nvl(lag(x) over (order by x),x) != x-1 7 then x end loval 8 from t)) 9 group by loval; RANGES -------------------- 2-4 7-8 12-13 15-17 19-20
  • 138. 138 SQL> select 2 min(x)||'-'|| 3 case when min (x) = max (x) 4 then min(x) 5 else max(x) 6 end rng 7 from 8 (select X 9 , row_number() over (order by X) rn 10 from t 11 ) 12 group by x - rn 13 order by min(x); RNG ---------------- 2-4 7-8 12-13 15-17 19-20
  • 140. sql_string = "select * from ACCOUNTS where ACCT_NO in ( :bindvar )" EXEC SQL PREPARE sql_string; ORA-01722: invalid number 123,456,789
  • 141. SQL> exec :acct = '123,456,789' SQL> select substr(:acct, 2 loc+1,nvl( 3 lead(loc) over ( order by loc ) – loc-1, 4 length(:acct)-loc) 5 ) list_as_rows 6 from ( 7 select distinct (instr(:acct,',',1,level)) loc 8 from dual 9 connect by level < length(:acct)- 10 length(replace(:acct,','))+1 11 ); LIST_AS_ROWS -------------------- 123 456 789
  • 142. SQL> with MY_LIST as select substr(:acct, 2 loc+1,nvl( 3 lead(loc) over ( order by loc ) – loc-1, 4 length(:acct)-loc) 5 ) val 6 from ( 7 select distinct (instr(:acct,',',1,level)) loc 8 from dual 9 connect by level < length(:acct)- 10 length(replace(:acct,','))+1 11 ) 12 select * 13 from ACCOUNTS 14 where ACCT_NO in ( select val from MY_LIST)
  • 147. 147 SQL> select deptno, ename 2 from emp 3 order by 1,2; DEPTNO ENAME ---------- ---------- 10 CLARK 10 KING 10 MILLER 20 ADAMS 20 FORD 20 JONES 20 SCOTT 20 SMITH 30 ALLEN 30 BLAKE 30 JAMES 30 MARTIN 30 TURNER 30 WARD
  • 148. 148 DEPTNO MEMBERS ---------- ------------------------------------- 10 CLARK,KING,MILLER 20 SMITH,JONES,SCOTT,ADAMS,FORD 30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
  • 150. SQL> select deptno , rtrim(ename,',') enames 2 from ( select deptno,ename,rn 3 from emp 4 model 5 partition by (deptno) 6 dimension by ( 7 row_number() over 8 (partition by deptno order by ename) rn 9 ) 10 measures (cast(ename as varchar2(40)) ename) 11 rules 12 ( ename[any] 13 order by rn desc = ename[cv()]||','||ename[cv()+1]) 14 ) 15 where rn = 1 16 order by deptno; DEPTNO ENAMES ---------- ---------------------------------------- 10 CLARK,KING,MILLER 20 ADAMS,FORD,JONES,SCOTT,SMITH 30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD - Rob Van Wijk
  • 151. SQL> select deptno, 2 substr(max(sys_connect_by_path(ename, ',')), 2) members 3 from (select deptno, ename, 4 row_number () 5 over (partition by deptno order by empno) rn 6 from emp) 7 start with rn = 1 8 connect by prior rn = rn - 1 9 and prior deptno = deptno 10 group by deptno 11 / DEPTNO MEMBERS ---------- --------------------------------------------------------- 30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES 20 SMITH,JONES,SCOTT,ADAMS,FORD 10 CLARK,KING,MILLER - Anon
  • 152. SQL> select deptno, 2 xmltransform 3 ( sys_xmlagg 4 ( sys_xmlgen(ename) 5 ), 6 xmltype 7 ( 8 '<?xml version="1.0"?><xsl:stylesheet version="1.0" 9 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 10 <xsl:template match="/"> 11 <xsl:for-each select="/ROWSET/ENAME"> 12 <xsl:value-of select="text()"/>;</xsl:for-each> 13 </xsl:template> 14 </xsl:stylesheet>' 15 ) 16 ).getstringval() members 17 from emp 18 group by deptno; DEPTNO MEMBERS ---------- -------------------------------------------------------- 10 CLARK;MILLER;KING; 20 SMITH;FORD;ADAMS;SCOTT;JONES; 30 ALLEN;JAMES;TURNER;BLAKE;MARTIN;WARD; - Laurent Schneider
  • 153. SQL> create or replace type string_agg_type as object 2 ( 3 total varchar2(4000), 4 5 static function 6 ODCIAggregateInitialize(sctx IN OUT string_agg_type ) 7 return number, 8 9 member function 10 ODCIAggregateIterate(self IN OUT string_agg_type , 11 value IN varchar2 ) 12 return number, 13 14 member function 15 ODCIAggregateTerminate(self IN string_agg_type, 16 returnValue OUT varchar2, 17 flags IN number) 18 return number, 19 20 member function 21 ODCIAggregateMerge(self IN OUT string_agg_type, 22 ctx2 IN string_agg_type) 23 return number 24 ); 25 /
  • 155. 155 SQL> select deptno, 2 listagg( ename, ',') 3 within group (order by empno) members 4 from emp 5 group by deptno; DEPTNO MEMBERS ---------- ----------------------------------------- 10 CLARK,KING,MILLER 20 SMITH,JONES,SCOTT,ADAMS,FORD 30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
  • 158. “Show me lowest salary for each department...” SQL> select deptno, min(sal) 2 from emp 3 group by deptno; “...and I need to know who has that lowest salary as well” SQL> select deptno, empno, min(sal) 2 from emp 3 group by deptno; ORA-00979: not a GROUP BY expression
  • 159. 159 SQL> select deptno, min(sal), min(empno) 2 KEEP ( dense_rank FIRST order by sal) empno 3 from emp 4 group by deptno 5 / DEPTNO MIN(SAL) EMPNO ---------- ---------- ---------- 10 1300 7934 20 800 7369 30 950 7900 Emp 7934 has the lowest salary in dept 10
  • 163. 163 SQL> select ename, sal, 2 100*cume_dist() over ( order by sal ) as pct 3 from emp 4 order by sal; ENAME SAL PCT ---------- ---------- ------- SMITH 800 7.14 JAMES 950 14.29 ADAMS 1100 21.43 WARD 1250 35.71 MARTIN 1250 35.71 MILLER 1300 42.86 TURNER 1500 50.00 ALLEN 1600 57.14 CLARK 2450 64.29 BLAKE 2850 71.43 JONES 2975 78.57 FORD 3000 92.86 SCOTT 3000 92.86 KING 5000 100.00
  • 164. 164 "what is the 60th percentile salary in the company?"
  • 165. 165 SQL> select ename, sal, 2 100*cume_dist() over ( order by sal ) as pct 3 from emp 4 order by sal; ENAME SAL PCT ---------- ---------- ------- SMITH 800 7.14 JAMES 950 14.29 ADAMS 1100 21.43 WARD 1250 35.71 MARTIN 1250 35.71 MILLER 1300 42.86 TURNER 1500 50.00 ALLEN 1600 57.14 CLARK 2450 64.29 BLAKE 2850 71.43 JONES 2975 78.57 FORD 3000 92.86 SCOTT 3000 92.86 KING 5000 100.00
  • 166. 166 SQL> select ename, sal, 2 100*cume_dist() over ( order by sal ) as pct 3 from emp 4 order by sal; ENAME SAL PCT ---------- ---------- ------- SMITH 800 7.14 JAMES 950 14.29 ADAMS 1100 21.43 WARD 1250 35.71 MARTIN 1250 35.71 MILLER 1300 42.86 TURNER 1500 50.00 ALLEN 1600 57.14 CLARK 2450 64.29 BLAKE 2850 71.43 JONES 2975 78.57 FORD 3000 92.86 SCOTT 3000 92.86 KING 5000 100.00
  • 167. 167 SQL> select 2 percentile_disc(0.6) 3 within group 4 (order by sal) as dicrete_pct, 5 percentile_cont(0.6) 6 within group 7 (order by sal) as continuous_pct 8 from emp; DICRETE_PCT CONTINUOUS_PCT ----------- -------------- 2450 2280
  • 171. SQL> select deptno, avg(distinct sal) median 2 from 3 (select cp1.deptno, cp1.sal 4 from emp cp1, emp cp2 5 where cp1.deptno = cp2.deptno 6 group by cp1.deptno, cp1.sal 7 having sum(decode(cp1.sal, cp2.sal, 1, 0)) >= 8 abs(sum(sign(cp1.sal - cp2.sal)))) 9 group by deptno 10 / DEPTNO MEDIAN ---------- ---------- 10 3725 20 2975 30 1375 40 1300 wth?
  • 172. SQL> select 2 deptno, 3 percentile_cont(0.5) 4 within group (order by sal) as median 5 from emp 6 group by deptno; SQL> select 2 deptno, 3 median(sal) 4 from emp 5 group by deptno; DEPTNO MEDIAN(SAL) ---------- ----------- 10 3725 20 2975 30 1375 40 1300
  • 174. 174 "if I was paid $3000, where would I rank in each department?"
  • 175. 175 SQL> select 2 deptno, 3 rank(3000) within group 4 ( order by sal ) as ranking 5 from emp 6 group by deptno; DEPTNO RANKING ---------- ---------- 10 2 20 4 30 7 40 2
  • 178. SQL> select 2 empno, 3 ename, 4 sal, 5 100*ratio_to_report(sal) over () as pct 6 from emp; EMPNO ENAME SAL PCT ---------- ---------- ---------- ------- 7521 WARD 1250 4.69 7566 JONES 2975 11.17 7654 MARTIN 1250 4.69 7698 BLAKE 2850 10.70 7782 CLARK 2450 9.20 7788 SCOTT 3000 11.27 7839 KING 5000 18.78 7844 TURNER 1500 5.63 7876 ADAMS 1100 4.13 7900 JAMES 950 3.57 7902 FORD 3000 11.27 7934 MILLER 1300 4.88
  • 179. 179 3 more things ... not really analytic ?
  • 181. 181 SQL> select * 2 from timeslots; HR -- 8 9 10 11 12 13 14 15 16 SQL> select * 2 from bookings; HR ROOM WHO ------- ---------- ------- 8 Room2 PETE 9 Room1 JOHN 11 Room1 MIKE 14 Room2 JILL 15 Room2 JANE 16 Room1 SAM
  • 183. 183 SQL> SELECT hrs.hr, t1.room, t1.who 2 from timeslots hrs 3 left outer join bookings t1 4 on hrs.hr = t1.hr 5 order by 1 HR ROOM WHO ------- ---------- ---------- 8 Room2 PETE 9 Room1 JOHN 10 11 Room1 MIKE 12 13 14 Room2 JILL 15 Room2 JANE 16 Room1 SAM
  • 184. 184 bookings by hour per room
  • 185. 185 HR ROOM WHO ------- ---------- ---------- 8 Room2 PETE 9 10 11 12 13 14 Room2 JILL 15 Room2 JANE 16 HR ROOM WHO ------- ---------- ---------- 8 9 Room1 JOHN 10 11 Room1 MIKE 12 13 14 15 16 Room1 SAM
  • 186. 186 SQL> select * 2 from timeslots; HR -- 8 9 10 11 12 13 14 15 16 x "Room 1" x "Room 2" ... x "Room n"
  • 188. 188 SQL> SELECT hrs.hr, t1.room, t1.who 2 FROM bookings t1 3 PARTITION BY (t1.room) 4 RIGHT OUTER JOIN timeslots ON (hrs.hr = t1.hr) 5 order by 1,2 HR ROOM WHO --------- ---------- ---------- 8 Room1 9 Room1 JOHN 10 Room1 11 Room1 MIKE 12 Room1 13 Room1 14 Room1 15 Room1 16 Room1 SAM 8 Room2 PETE 9 Room2 10 Room2 11 Room2 12 Room2 13 Room2 14 Room2 JILL 15 Room2 JANE 16 Room2
  • 190. SQL> select 2 object_id, 3 width_bucket(object_id, 4 1000, 5 90000, 6 10) bucket 7 from dba_objects OBJECT_ID BUCKET ---------- ---------- 913 0 ... 3231 1 ... 5858 1 ... 14920 2 ... 42421 5 ... 91635 11 < min > max 1 .. buckets
  • 193. 193 SQL> select employee_id, last_name 2 from employees 3 order by employee_id 4 fetch first 5 rows only;
  • 196. 197 cannot be a predicate
  • 197. SQL> select ename, deptno, sal 2 from emp 3 where 4 sum(sal) over 5 ( partition by deptno) > 10; sum(sal) over * ERROR at line 4: ORA-00934: group function is not allowed here
  • 199. 200 SQL> select ename, deptno, sal 2 from ( 3 select ename, deptno, sal, 4 sum(sal) over 5 ( partition by deptno) as deptsal 6 from emp 7 ) 8 where deptsal > 10;
  • 201. 202 create view RANKED_ACCOUNTS as select account_num, customer_name, acct_type_code, rank() over ( order by gross_sales ) as seq from ACCOUNTS; indexed column
  • 202. 203 SQL> select * from RANKED_ACCOUNTS 2 where ACCOUNT_NUM = 12345 ------------------------------------------------ | Id | Operation | Name | ------------------------------------------------ | 0 | SELECT STATEMENT | | | 1 | VIEW | RANKED_ACCOUNTS | | 2 | WINDOW SORT | | | 3 | TABLE ACCESS FULL| ACCOUNTS | ------------------------------------------------
  • 204. recall
  • 205. SQL> select deptno, 2 listagg( ename, ',') 3 within group (order by empno) 4 from emp 5 group by deptno;
  • 209. 210 "Find 10 consecutive deposits in a 24 hour period, then a withdrawal within three days of the last deposit, at a different branch"
  • 210. ACCT TSTAMP WTHD_TSTAMP T AMT ---------- ------------------ ------------------ - ---------- 54261 25/01/13 17:20:55 D 100 54261 25/01/13 17:56:58 D 165 54261 26/01/13 11:24:14 D 30 54261 26/01/13 11:47:53 D 45 54261 26/01/13 12:59:38 D 100 54261 26/01/13 13:26:04 D 80 54261 26/01/13 14:41:09 D 50 54261 26/01/13 14:53:12 D 50 54261 26/01/13 15:15:05 D 50 54261 26/01/13 15:51:17 D 50 54261 26/01/13 16:15:02 D 120 54261 26/01/13 16:36:51 D 100 54261 26/01/13 16:55:09 D 100 54261 26/01/13 18:07:17 26/01/13 18:07:17 W -500
  • 215. SQL> select acct, tstamp, wthd_tstamp, txn_type, amt 2 from account_txns 3 MATCH_RECOGNIZE 4 ( 5 partition by acct 6 order by tstamp 7 measures 8 dep.tstamp dep_tstamp, 9 wthd.tstamp wthd_tstamp 10 11 all rows per match 12 pattern ( dep{10,} wthd ) 13 define 14 dep as 15 txn_type = 'D', 16 wthd as 17 txn_type = 'W' 18 and last(dep.tstamp)-first(dep.tstamp) < interval '1' day 19 and wthd.tstamp - last(dep.tstamp) < interval '3' day 20 and wthd.loc_id != last(dep.loc_id) 21 )
  • 216. SQL> select acct, tstamp, wthd_tstamp, txn_type, amt 2 from account_txns 3 MATCH_RECOGNIZE 4 ( 5 partition by acct 6 order by tstamp 7 measures 8 dep.tstamp dep_tstamp, 9 wthd.tstamp wthd_tstamp 10 11 all rows per match 12 pattern ( dep{10,} wthd ) 13 define 14 dep as 15 txn_type = 'D', 16 wthd as 17 txn_type = 'W' 18 and last(dep.tstamp)-first(dep.tstamp) < interval '1' day 19 and wthd.tstamp - last(dep.tstamp) < interval '3' day 20 and wthd.loc_id != last(dep.loc_id) 21 )
  • 217. SQL> select acct, tstamp, wthd_tstamp, txn_type, amt 2 from account_txns 3 MATCH_RECOGNIZE 4 ( 5 partition by acct 6 order by tstamp 7 measures 8 dep.tstamp dep_tstamp, 9 wthd.tstamp wthd_tstamp 10 11 all rows per match 12 pattern ( dep{10,} wthd ) 13 define 14 dep as 15 txn_type = 'D', 16 wthd as 17 txn_type = 'W' 18 and last(dep.tstamp)-first(dep.tstamp) < interval '1' day 19 and wthd.tstamp - last(dep.tstamp) < interval '3' day 20 and wthd.loc_id != last(dep.loc_id) 21 )
  • 224. 225 Thank you youtube bit.ly/youtube-connor blog bit.ly/blog-connor twitter bit.ly/twitter-connor