Oracle Analytic Function - Oracle/PLSQL Window Function






Cumulative Sum

You can perform window function with the following functions: SUM(), AVG(), MAX(), MIN(), COUNT(), VARIANCE(), and STDDEV().

The following query performs a cumulative sum to compute the cumulative salaries amount, starting with each department.

SUM(amount) computes the sum of an amount. The outer SUM() computes the cumulative amount. ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW defines the start and end of the window. The start is set to UNBOUNDED PRECEDING. UNBOUNDED PRECEDING means that the start of the window is fixed at the first row in the result set. CURRENT ROW sets the end of the window. CURRENT ROW represents the current row in the result set.


CREATE TABLE EMP (EMPNO NUMBER(4) NOT NULL,
                  ENAME VARCHAR2(10),
                  JOB VARCHAR2(9),
                  SAL NUMBER(7, 2),
                  DEPTNO NUMBER(2));
-- from  www .j  a  v  a 2 s .co m
INSERT INTO EMP VALUES (1, 'SMITH', 'CLERK',     800,    20);
INSERT INTO EMP VALUES (2, 'ALLEN', 'SALESMAN', 1600,    30);
INSERT INTO EMP VALUES (3, 'WARD',  'SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (4, 'JONES', 'MANAGER',  2975,    20);
INSERT INTO EMP VALUES (5, 'MARTIN','SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (6, 'BLAKE', 'MANAGER',  2850,    30);
INSERT INTO EMP VALUES (7, 'CLARK', 'MANAGER',  2850,    10);
INSERT INTO EMP VALUES (8, 'SCOTT', 'ANALYST',  3000,    20);
INSERT INTO EMP VALUES (9, 'KING',  'PRESIDENT',3000,    10);
INSERT INTO EMP VALUES (10,'TURNER','SALESMAN', 1500,    30);
INSERT INTO EMP VALUES (11,'ADAMS', 'CLERK',    1500,    20);

SQL> SELECT deptno, SUM(sal) AS dept_salary,
  2  SUM(SUM(sal)) OVER (ORDER BY deptno ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
  3  AS cumulative_amount
  4  FROM emp
  5  GROUP BY deptno
  6  ORDER BY deptno;

    DEPTNO DEPT_SALARY CUMULATIVE_AMOUNT
---------- ----------- -----------------
        10        5850              5850
        20        8275             14125
        30        8450             22575

SQL>

The following query uses a cumulative sum to compute the cumulative salary amount, starting with employee number 2 to 6:


SQL> SELECT deptno, SUM(sal) AS month_amount,
  2  SUM(SUM(sal)) OVER--   ww w .  j  a  v  a  2s. c  o m
  3  (ORDER BY deptno ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS
  4  cumulative_amount
  5  FROM emp
  6  WHERE empno  BETWEEN 2 AND 6
  7  GROUP BY deptno
  8  ORDER BY deptno;

    DEPTNO MONTH_AMOUNT CUMULATIVE_AMOUNT
---------- ------------ -----------------
        20         2975              2975
        30         6950              9925

SQL>




Moving Average

The following query computes the moving average of the salary amount between the current department and the previous three departments: ROWS BETWEEN 3 PRECEDING AND CURRENT ROW defines the start of the window as including the three rows preceding the current row; the end of the window is the current row being processed.


CREATE TABLE EMP (EMPNO NUMBER(4) NOT NULL,
                  ENAME VARCHAR2(10),
                  JOB VARCHAR2(9),
                  SAL NUMBER(7, 2),
                  DEPTNO NUMBER(2));
-- from  w  w  w .  j  a v  a2  s  . co  m
INSERT INTO EMP VALUES (1, 'SMITH', 'CLERK',     800,    20);
INSERT INTO EMP VALUES (2, 'ALLEN', 'SALESMAN', 1600,    30);
INSERT INTO EMP VALUES (3, 'WARD',  'SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (4, 'JONES', 'MANAGER',  2975,    20);
INSERT INTO EMP VALUES (5, 'MARTIN','SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (6, 'BLAKE', 'MANAGER',  2850,    30);
INSERT INTO EMP VALUES (7, 'CLARK', 'MANAGER',  2850,    10);
INSERT INTO EMP VALUES (8, 'SCOTT', 'ANALYST',  3000,    20);
INSERT INTO EMP VALUES (9, 'KING',  'PRESIDENT',3000,    10);
INSERT INTO EMP VALUES (10,'TURNER','SALESMAN', 1500,    30);
INSERT INTO EMP VALUES (11,'ADAMS', 'CLERK',    1500,    20);

SQL> SELECT
  2  deptno, SUM(sal) AS month_amount,
  3  AVG(SUM(sal)) OVER (ORDER BY deptno ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
  4  AS moving_average
  5  FROM emp
  6  GROUP BY deptno
  7  ORDER BY deptno;

    DEPTNO MONTH_AMOUNT MOVING_AVERAGE
---------- ------------ --------------
        10         5850           5850
        20         8275         7062.5
        30         8450           7525

SQL>




Centered Average

The following query computes the moving average of the salary amount centered between the previous and next department from the current department: ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING defines the start of the window as including the row preceding the current row being processed. The end of the window is the row following the current row.


CREATE TABLE EMP (EMPNO NUMBER(4) NOT NULL,
                  ENAME VARCHAR2(10),
                  JOB VARCHAR2(9),
                  SAL NUMBER(7, 2),
                  DEPTNO NUMBER(2));
-- from  w  ww . j  a v  a  2 s  . c o m
INSERT INTO EMP VALUES (1, 'SMITH', 'CLERK',     800,    20);
INSERT INTO EMP VALUES (2, 'ALLEN', 'SALESMAN', 1600,    30);
INSERT INTO EMP VALUES (3, 'WARD',  'SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (4, 'JONES', 'MANAGER',  2975,    20);
INSERT INTO EMP VALUES (5, 'MARTIN','SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (6, 'BLAKE', 'MANAGER',  2850,    30);
INSERT INTO EMP VALUES (7, 'CLARK', 'MANAGER',  2850,    10);
INSERT INTO EMP VALUES (8, 'SCOTT', 'ANALYST',  3000,    20);
INSERT INTO EMP VALUES (9, 'KING',  'PRESIDENT',3000,    10);
INSERT INTO EMP VALUES (10,'TURNER','SALESMAN', 1500,    30);
INSERT INTO EMP VALUES (11,'ADAMS', 'CLERK',    1500,    20);

SQL> SELECT deptno, SUM(sal) AS dept_amount,
  2  AVG(SUM(sal)) OVER (ORDER BY deptno ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
  3  AS moving_average
  4  FROM emp
  5  GROUP BY deptno
  6  ORDER BY deptno;

    DEPTNO DEPT_AMOUNT MOVING_AVERAGE
---------- ----------- --------------
        10        5850         7062.5
        20        8275           7525
        30        8450         8362.5

SQL>

FIRST_VALUE()

FIRST_VALUE() gets the first rows in a window.


CREATE TABLE EMP (EMPNO NUMBER(4) NOT NULL,
                  ENAME VARCHAR2(10),
                  JOB VARCHAR2(9),
                  SAL NUMBER(7, 2),
                  DEPTNO NUMBER(2));
-- from w ww . ja  v a  2 s .  co m
INSERT INTO EMP VALUES (1, 'SMITH', 'CLERK',     800,    20);
INSERT INTO EMP VALUES (2, 'ALLEN', 'SALESMAN', 1600,    30);
INSERT INTO EMP VALUES (3, 'WARD',  'SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (4, 'JONES', 'MANAGER',  2975,    20);
INSERT INTO EMP VALUES (5, 'MARTIN','SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (6, 'BLAKE', 'MANAGER',  2850,    30);
INSERT INTO EMP VALUES (7, 'CLARK', 'MANAGER',  2850,    10);
INSERT INTO EMP VALUES (8, 'SCOTT', 'ANALYST',  3000,    20);
INSERT INTO EMP VALUES (9, 'KING',  'PRESIDENT',3000,    10);
INSERT INTO EMP VALUES (10,'TURNER','SALESMAN', 1500,    30);
INSERT INTO EMP VALUES (11,'ADAMS', 'CLERK',    1500,    20);

SQL> SELECT deptno, SUM(sal) AS dept_amount,
  2  FIRST_VALUE(SUM(sal)) OVER (ORDER BY deptno ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
  3  AS previous_month_amount
  4  FROM emp
  5  GROUP BY deptno
  6  ORDER BY deptno;

    DEPTNO DEPT_AMOUNT PREVIOUS_MONTH_AMOUNT
---------- ----------- ---------------------
        10        5850                  5850
        20        8275                  5850
        30        8450                  8275

SQL>

LAST_VALUE()

LAST_VALUE() gets the last rows in a window.


CREATE TABLE EMP (EMPNO NUMBER(4) NOT NULL,
                  ENAME VARCHAR2(10),
                  JOB VARCHAR2(9),
                  SAL NUMBER(7, 2),
                  DEPTNO NUMBER(2));
-- from  w  w w .  j  ava  2  s  .c o  m
INSERT INTO EMP VALUES (1, 'SMITH', 'CLERK',     800,    20);
INSERT INTO EMP VALUES (2, 'ALLEN', 'SALESMAN', 1600,    30);
INSERT INTO EMP VALUES (3, 'WARD',  'SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (4, 'JONES', 'MANAGER',  2975,    20);
INSERT INTO EMP VALUES (5, 'MARTIN','SALESMAN', 1250,    30);
INSERT INTO EMP VALUES (6, 'BLAKE', 'MANAGER',  2850,    30);
INSERT INTO EMP VALUES (7, 'CLARK', 'MANAGER',  2850,    10);
INSERT INTO EMP VALUES (8, 'SCOTT', 'ANALYST',  3000,    20);
INSERT INTO EMP VALUES (9, 'KING',  'PRESIDENT',3000,    10);
INSERT INTO EMP VALUES (10,'TURNER','SALESMAN', 1500,    30);
INSERT INTO EMP VALUES (11,'ADAMS', 'CLERK',    1500,    20);

SQL> SELECT deptno, SUM(sal) AS dept_amount,
  2  LAST_VALUE(SUM(sal)) OVER(ORDER BY deptno ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
  3  AS next_month_amount
  4  FROM emp
  5  GROUP BY deptno
  6  ORDER BY deptno;

    DEPTNO DEPT_AMOUNT NEXT_MONTH_AMOUNT
---------- ----------- -----------------
        10        5850              8275
        20        8275              8450
        30        8450              8450

SQL>