analytic functions in oracle 8i and 9i

16
8/8/2019 Analytic Functions in Oracle 8i and 9i http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 1/16  Analytic Functions in Oracle 8i and 9i Contents Overview and Introduction How Analytic Functions Work The Syntax Calculate a running Total Top-N Queries  Example 1  Example 2 Windows  Range Windows  Compute average salary for defined range  Row Windows  Accessing Rows Around Your Current Row LAG LEAD Determine the First Value / Last Value of a Group Crosstab or Pivot Queries Conclusion Links and Documents Overview Analytic Functions, which have been available since Oracle 8.1.6, are designed to address such problems as "Calculate a running total", "Find percentages within a group", "Top-N queries", "Compute a moving average" and many more. Most of these problems can be solved using standard PL/SQL, however the performance is often not what it should be. Analytic Functions add extensions to the SQL language that not only make these operations easier to code; they make them faster than could be achieved with pure SQL or PL/SQL. These extensions are currently under review by the ANSI SQL committee for inclusion in the SQL specification. How Analytic Functions Work ? Analytic functions compute an aggregate value based on a group of rows. They differ from aggregate functions in that they return multiple rows for each group. The group of rows is called a window and is defined by the analytic clause. For each row, a "sliding" window of rows is defined. The window determines the range of rows used to perform the calculations for the "current row". Window sizes can be based on either a physical number of rows or a logical interval such as time. Analytic functions are the last set of operations performed in a query except for the final ORDER BY clause. All joins and all WHERE, GROUP BY, and HAVING clauses are completed before the analytic functions are processed. Therefore, analytic functions can appear only in the select list or ORDER BY clause. The Syntax

Upload: paritosh-sharma

Post on 10-Apr-2018

217 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 1/16

 

Analytic Functions in Oracle 8i and 9i

Contents

Overview and Introduction

How Analytic Functions WorkThe Syntax

Calculate a running TotalTop-N Queries

  Example 1  Example 2

Windows  Range Windows

  Compute average salary for defined range  Row Windows

  Accessing Rows Around Your Current RowLAG

LEADDetermine the First Value / Last Value of a Group

Crosstab or Pivot QueriesConclusion

Links and Documents 

Overview

Analytic Functions, which have been available since Oracle 8.1.6, are designed toaddress such problems as "Calculate a running total", "Find percentages within a

group", "Top-N queries", "Compute a moving average" and many more. Most of these problems can be solved using standard PL/SQL, however the performance is

often not what it should be. Analytic Functions add extensions to the SQL languagethat not only make these operations easier to code; they make them faster than

could be achieved with pure SQL or PL/SQL. These extensions are currently underreview by the ANSI SQL committee for inclusion in the SQL specification.

How Analytic Functions Work ?

Analytic functions compute an aggregate value based on a group of rows.

They differ from aggregate functions in that they return multiple rows for eachgroup. The group of rows is called a window and is defined by the analytic clause.

For each row, a "sliding" window of rows is defined. The window determines therange of rows used to perform the calculations for the "current row". Window sizes

can be based on either a physical number of rows or a logical interval such as time.

Analytic functions are the last set of operations performed in a query except for the

final ORDER BY clause. All joins and all WHERE, GROUP BY, and HAVING clauses arecompleted before the analytic functions are processed. Therefore, analytic functions

can appear only in the select list or ORDER BY clause.

The Syntax

Page 2: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 2/16

The Syntax of analytic functions is rather straightforward in appearance

Analytic-Function(<Argument>,<Argument>,...)OVER (<Query-Partition-Clause>

<Order-By-Clause><Windowing-Clause>

)

o Analytic-Function

Specify the name of an analytic function, Oracle actually provides many analytic

functions such as AVG, CORR, COVAR_POP , COVAR_SAMP , COUNT , CUME_DIST ,DENSE_RANK , FIRST , FIRST_VALUE , LAG, LAST , LAST_VALUE , LEAD, MAX , MIN ,

NTILE , PERCENT_RANK , PERCENTILE_CONT , PERCENTILE_DISC , RANK ,

RATIO_TO_REPORT , STDDEV , STDDEV_POP , STDDEV_SAMP , SUM , VAR_POP ,VAR_SAMP , VARIANCE .

o Arguments

Analytic functions take 0 to 3 arguments.

o Query-Partition-Clause

The PARTITION BY clause logically breaks a single result set into N groups, according

to the criteria set by the partition expressions. The words "partition" and "group" areused synonymously here. The analytic functions are applied to each group

independently, they are reset for each group.

o Order-By-Clause

The ORDER BY clause specifies how the data is sorted within each group (partition).This will definitely affect the outcome of any analytic function.

o Windowing-Clause

The windowing clause gives us a way to define a sliding or anchored window of data,

on which the analytic function will operate, within a group. This clause can be usedto have the analytic function compute its value based on any arbitrary sliding or

anchored window within a group. More information on windows can be found here.

Example: Calculate a running Total

This example shows the cumulative salary within a department row by row, with

each row including a summation of the prior rows salary.

set autotrace traceonly explainbreak on deptno skip 1column ename format A6column deptno format 999

Page 3: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 3/16

column sal format 99999column seq format 999

SELECT ename "Ename", deptno "Deptno", sal "Sal",SUM(sal)

OVER (ORDER BY deptno, ename) "Running Total",SUM(SAL)OVER (PARTITION BY deptno

ORDER BY ename) "Dept Total",ROW_NUMBER()OVER (PARTITION BY deptno

ORDER BY ENAME) "Seq"FROM empORDER BY deptno, ename/ 

Ename Deptno Sal Running Total Dept Total Seq------ ------ ------ ------------- ---------- ----

CLARK 10 2450 2450 2450 1KING 5000 7450 7450 2MILLER 1300 8750 8750 3

ADAMS 20 1100 9850 1100 1FORD 3000 12850 4100 2JONES 2975 15825 7075 3SCOTT 3000 18825 10075 4SMITH 800 19625 10875 5

ALLEN 30 1600 21225 1600 1BLAKE 2850 24075 4450 2JAMES 950 25025 5400 3MARTIN 1250 26275 6650 4

TURNER 1500 27775 8150 5WARD 1250 29025 9400 6 

Execution Plan---------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE1 0 WINDOW (SORT)2 1 TABLE ACCESS (FULL) OF 'EMP'

Statistics---------------------------------------------------

0 recursive calls0 db block gets3 consistent gets

0 physical reads0 redo size

1658 bytes sent via SQL*Net to client503 bytes received via SQL*Net from client2 SQL*Net roundtrips to/from client1 sorts (memory)0 sorts (disk)

14 rows processed

Page 4: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 4/16

The example shows how to calculate a "Running Total" for the entire query. This is

done using the entire ordered result set, via SUM(sal) OVER (ORDER BY deptno,ename). 

Further, we were able to compute a running total within each department, a total

that would be reset at the beginning of the next department. The PARTITION BY deptno in that SUM(sal) caused this to happen, a partitioning clause was specified in

the query in order to break the data up into groups.

The ROW_NUMBER () function is used to sequentially number the rows returned

in each group, according to our ordering criteria (a "Seq" column was added to inorder to display this position).

The execution plan shows, that the whole query is very well performed with only 3consistent gets, this can never be accomplished with standard SQL or even PL/SQL.

Top-N Queries

How can we get the Top-N records by some set of fields ?

Prior to having access to these analytic functions, questions of this nature wereextremely difficult to answer.

There are some problems with Top-N queries however; mostly in the way peoplephrase them. It is something to be careful about when designing reports. Consider

this seemingly sensible request:

I would like the top three paid sales reps by department  

The problem with this question is that it is ambiguous. It is ambiguous because of 

repeated values, there might be four people who all make the same salary, whatshould we do then ?

Let's look at three examples, all use the well known table EMP.

Example 1

Sort the sales people by salary from greatest to least. Give the first three rows. If 

there are less then three people in a department, this will return less than threerecords.

set auto trace on explain

break on deptno skip 1

SELECT * FROM (SELECT deptno, ename, sal, ROW_NUMBER()OVER (PARTITION BY deptno ORDER BY sal DESC

) Top3 FROM emp)

 WHERE Top3 <= 3

Page 5: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 5/16

/

DEPTNO ENAME SAL TOP3---------- ---------- ---------- ----------

10 KING 5000 1

CLARK 2450 2MILLER 1300 3

20 SCOTT 3000 1FORD 3000 2JONES 2975 3

30 BLAKE 2850 1ALLEN 1600 2TURNER 1500 3

9 rows selected.

Execution Plan--------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE1 0 VIEW2 1 WINDOW (SORT)3 2 TABLE ACCESS (FULL) OF 'EMP' 

This query works by sorting each partition (or group, which is the deptno), in a

descending order, based on the salary column and then assigning a sequential rownumber to each row in the group as it is processed. The use of a WHERE clause after

doing this to get just the first three rows in each partition.

Example 2

Give me the set of sales people who make the top 3 salaries - that is, find the set of 

distinct salary amounts, sort them, take the largest three, and give me everyone

who makes one of those values.

SELECT * FROM (SELECT deptno, ename, sal,

DENSE_RANK()OVER (PARTITION BY deptno ORDER BY sal desc

) TopN FROM emp)

 WHERE TopN <= 3

ORDER BY deptno, sal DESC/

DEPTNO ENAME SAL TOPN---------- ---------- ---------- ----------

10 KING 5000 1CLARK 2450 2MILLER 1300 3

  20 SCOTT 3000 1 <--- !

Page 6: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 6/16

FORD 3000 1 <---!JONES 2975 2ADAMS 1100 3

30 BLAKE 2850 1

ALLEN 1600 230 TURNER 1500 3

10 rows selected.

Execution Plan--------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE1 0 VIEW2 1 WINDOW (SORT PUSHED RANK)3 2 TABLE ACCESS (FULL) OF 'EMP' 

Here the DENSE_RANK function was used to get the top three salaries. We

assigned the dense rank to the salary column and sorted it in a descending order.

The DENSE_RANK function computes the rank of a row in an ordered group of rows.

The ranks are consecutive integers beginning with 1. The largest rank value is thenumber of unique values returned by the query. Rank values are not skipped in the

event of ties. Rows with equal values for the ranking criteria receive the same rank.

The DENSE_RANK function does not skip numbers and will assign the same number

to those rows with the same value. Hence, after the result set is built in the inlineview, we can simply select all of the rows with a dense rank of three or less, this

gives us everyone who makes the top three salaries by department number.

Windows

The windowing clause gives us a way to define a sliding or anchored window of data,on which the analytic function will operate, within a group. The default window is

an anchored window that simply starts at the first row of a group an continues to thecurrent row.

We can set up windows based on two criteria: RANGES of data values or ROWSoffset from the current row. It can be said, that the existance of an ORDER BY in

an analytic function will add a default window clause of RANGE UNBOUNDED

PRECEDING. That says to get all rows in our partition that came before us asspecified by the ORDER BY clause.

Let's look at an example with a sliding window within a group and compute the sum

of the current row's SAL column plus the previous 2 rows in that group. If we need areport that shows the sum of the current employee's salary with the preceding two

salaries within a departement, it would look like this.

break on deptno skip 1column ename format A6column deptno format 999

Page 7: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 7/16

column sal format 99999

SELECT deptno "Deptno", ename "Ename", sal "Sal",SUM(SAL)OVER (PARTITION BY deptno

ORDER BY ename  ROWS 2 PRECEDING) "Sliding Total"FROM empORDER BY deptno, ename/

Deptno Ename Sal Sliding Total------ ------ ------ -------------

10 CLARK 2450 2450KING 5000 7450MILLER 1300 8750

20 ADAMS 1100 1100FORD 3000 4100

  JONES 2975 7075 ^SCOTT 3000 8975 |SMITH 800 6775 \-- Sliding Window

30 ALLEN 1600 1600BLAKE 2850 4450JAMES 950 5400MARTIN 1250 5050TURNER 1500 3700WARD 1250 4000 

The partition clause makes the SUM (sal) be computed within each department,independent of the other groups. Tthe SUM (sal) is ' reset ' as the department

changes. The ORDER BY ENAME clause sorts the data within each department byENAME; this allows the window clause: ROWS 2 PRECEDING, to access the 2

rows prior to the current row in a group in order to sum the salaries.

For example, if you note the SLIDING TOTAL value for SMITH is 6 7 7 5, which is

the sum of 800, 3000, and 2975. That was simply SMITH's row plus the salary fromthe preceding two rows in the window.

Range Windows

Range windows collect rows together based on a WHERE clause. If I say ' range 5

preceding ' for example, this will generate a sliding window that has the set of all

preceding rows in the group such that they are within 5 units of the current row.These units may either be numeric comparisons or date comparisons and it is notvalid to use RANGE with datatypes other than numbers and dates.

Example

Count the employees which where hired within the last 100 days preceding the own

hiredate. The range window goes back 100 days from the current row's hiredate and

Page 8: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 8/16

then counts the rows within this range. The solution ist to use the following window

specification:

COUNT(*) OVER (ORDER BY hiredate ASC RANGE 100 PRECEDING) 

column ename heading "Name" format a8column hiredate heading "Hired" format a10column hiredate_pre heading "Hired-100" format a10column cnt heading "Cnt" format 99

SELECT ename, hiredate, hiredate-100 hiredate_pre,  COUNT(*)  OVER (

ORDER BY hiredate ASCRANGE 100 PRECEDING

) cntFROM empORDER BY hiredate ASC

/

Name Hired Hired-100 Cnt-------- ---------- ---------- ---SMITH 17-DEC-80 08-SEP-80 1ALLEN 20-FEB-81 12-NOV-80 2WARD 22-FEB-81 14-NOV-80 3JONES 02-APR-81 23-DEC-80 3BLAKE 01-MAY-81 21-JAN-81 4CLARK 09-JUN-81 01-MAR-81 3TURNER 08-SEP-81 31-MAY-81 2MARTIN 28-SEP-81 20-JUN-81 2KING 17-NOV-81 09-AUG-81 3

JAMES 03-DEC-81 25-AUG-81 5FORD 03-DEC-81 25-AUG-81 5MILLER 23-JAN-82 15-OCT-81 4SCOTT 09-DEC-82 31-AUG-82 1ADAMS 12-JAN-83 04-OCT-82 2

We ordered the single partition by hiredate ASC. If we look for example at the rowfor CLARK we can see that his hiredate was 09-JUN-81, and 100 days prior to that is

the date 01-MAR-81. If we look who was hired between 01-MAR-81 and 09-JUN-81,we find JONES (hired: 02-APR-81) and BLAKE (hired: 01-MAY-81). This are 3 rows

including the current row, this is what we see in the column "Cnt" of CLARK's row.

Compute average salary for defined range

As an example, compute the average salary of people hired within 100 days beforefor each employee. The query looks like this:

column ename heading "Name" format a8column hiredate heading "Hired" format a10column hiredate_pre heading "Hired-100" format a10column avg_sal heading "Avg-100" format 999999

Page 9: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 9/16

SELECT ename, hiredate, sal,   AVG(sal)

OVER (ORDER BY hiredate ASCRANGE 100 PRECEDING

) avg_salFROM empORDER BY hiredate ASC/

Name Hired SAL Avg-100-------- ---------- ---------- -------SMITH 17-DEC-80 800 800ALLEN 20-FEB-81 1600 1200WARD 22-FEB-81 1250 1217JONES 02-APR-81 2975 1942BLAKE 01-MAY-81 2850 2169CLARK 09-JUN-81 2450 2758TURNER 08-SEP-81 1500 1975MARTIN 28-SEP-81 1250 1375KING 17-NOV-81 5000 2583JAMES 03-DEC-81 950 2340FORD 03-DEC-81 3000 2340MILLER 23-JAN-82 1300 2563SCOTT 09-DEC-82 3000 3000ADAMS 12-JAN-83 1100 2050 

Look at CLARK again, since we understand his range window within the group. We

can see that the average salary of 2758 is equal to (2975+2850+2450)/3. This isthe average of the salaries for CLARK and the rows preceding CLARK, those of 

JONES and BLAKE. The data must be sorted in ascending order.

Row Windows

Row Windows are physical units; physical number of rows, to include in the window.For example you can calculate the average salary of a given record with the (up to

5) employees hired before them or after them as follows:

set numformat 9999SELECT ename, hiredate, sal,AVG(sal)OVER (ORDER BY hiredate ASC ROWS 5 PRECEDING) AvgAsc,

COUNT(*)OVER (ORDER BY hiredate ASC ROWS 5 PRECEDING) CntAsc,

AVG(sal)OVER (ORDER BY hiredate DESC ROWS 5 PRECEDING) AvgDes,

COUNT(*)OVER (ORDER BY hiredate DESC ROWS 5 PRECEDING) CntDes

FROM empORDER BY hiredate/

ENAME HIREDATE SAL AVGASC CNTASC AVGDES CNTDES

Page 10: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 10/16

---------- --------- ----- ------ ------ ------ ------SMITH 17-DEC-80 800 800 1 1988 6

  ALLEN 20-FEB-81 1600 1200 22104 6  WARD 22-FEB-81 1250 1217 32046 6JONES 02-APR-81 2975 1656 4 2671 6

BLAKE 01-MAY-81 2850 1895 5 2675 6CLARK 09-JUN-81 2450 1988 6 2358 6TURNER 08-SEP-81 1500 2104 6 2167 6MARTIN 28-SEP-81 1250 2046 6 2417 6KING 17-NOV-81 5000 2671 6 2392 6JAMES 03-DEC-81 950 2333 6 1588 4FORD 03-DEC-81 3000 2358 6 1870 5MILLER 23-JAN-82 1300 2167 6 1800 3SCOTT 09-DEC-82 3000 2417 6 2050 2ADAMS 12-JAN-83 1100 2392 6 1100 1 

The window consist of up to 6 rows, the current row and five rows " in front of " this

row, where " in front of " is defined by the ORDER BY clause. With ROW partitions,

we do not have the limitation of RANGE partition - the data may be of any type andthe order by may include many columns. Notice, that we selected out a COUNT(*) aswell. This is useful just to demonstrate how many rows went into making up a given

average. We can see clearly that for ALLEN's record, the average salary computationfor people hired before him used only 2 records whereas the computation for salaries

of people hired after him used 6.

Accessing Rows Around Your Current Row

Frequently you want to access data not only from the current row but the currentrow " in front of " or " behind " them. For example, let's say you need a report that

shows, by department all of the employees; their hire date; how many days before

was the last hire; how many days after was the next hire.

Using straight SQL this query would be difficult to write. Not only that but itsperformance would once again definitely be questionable. The approach I typically

took in the past was either to " select a select " or write a PL/SQL function thatwould take some data from the current row and " find " the previous and next rows

data. This worked, but introduce large overhead into both the development of thequery and the run-time execution of the query.

Using analytic functions, this is easy and efficient to do.

set echo on

column deptno format 99 heading Depcolumn ename format a6 heading Enamecolumn hiredate heading Hiredcolumn last_hire heading LastHiredcolumn days_last heading DaysLastcolumn next_hire heading NextHirecolumn days_next heading NextDays

break on deptno skip 1

Page 11: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 11/16

SELECT deptno, ename, hiredate,LAG(hiredate,1,NULL)OVER (PARTITION BY deptno

ORDER BY hiredate, ename) last_hire,hiredate - LAG(hiredate,1,NULL)

OVER (PARTITION BY deptnoORDER BY hiredate, ename) days_last,LEAD(hiredate,1,NULL)OVER (PARTITION BY deptno

ORDER BY hiredate, ename) next_hire,LEAD(hiredate,1,NULL)OVER (PARTITION BY deptno

ORDER BY hiredate, ename) - hiredate days_nextFROM empORDER BY deptno, hiredate/

Dep Ename Hired LastHired DaysLast NextHire NextDays--- ------ --------- --------- -------- --------- --------10 CLARK 09-JUN-81 17-NOV-81 161

KING 17-NOV-81 09-JUN-81  161 23-JAN-82 67MILLER 23-JAN-82 17-NOV-81 67

20 SMITH 17-DEC-80 02-APR-81 106JONES 02-APR-81 17-DEC-80 106 03-DEC-81 245FORD 03-DEC-81 02-APR-81 245 09-DEC-82 371SCOTT 09-DEC-82 03-DEC-81 371 12-JAN-83 34ADAMS 12-JAN-83 09-DEC-82 34

30 ALLEN 20-FEB-81 22-FEB-81 2WARD 22-FEB-81 20-FEB-81 2 01-MAY-81 68BLAKE 01-MAY-81 22-FEB-81 68 08-SEP-81 130

TURNER 08-SEP-81 01-MAY-81 130 28-SEP-81 20MARTIN 28-SEP-81 08-SEP-81 20 03-DEC-81 66JAMES 03-DEC-81 28-SEP-81 66 

The LEAD and LAG routines could be considered a way to " index into your

partitioned group ". Using these functions you can access any individual row. Notice

for example in the above printout, it shows that the record for KING includes thedata (in bold red font) from the prior row (LAST HIRE) and the next row (NEXT-

HIRE). We can access the fields in records preceding or following the current recordin an ordered partition easily.

LAG

LAG ( value_expr [, offset] [, default] )  OVER ( [query_partition_clause] order_by_clause )

LAG provides access to more than one row of a table at the same time without a

self join. Given a series of rows returned from a query and a position of the cursor,LAG provides access to a row at a given physical offset prior to that position.

If you do not specify offset , then its default is 1. The optional default value is

Page 12: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 12/16

returned if the offset goes beyond the scope of the window. If you do not specify

default , then its default value is null.

The following example provides, for each person in the EMP table, the salary of theemployee hired just before:

SELECT ename,hiredate,sal,LAG(sal, 1, 0)OVER (ORDER BY hiredate) AS PrevSal

FROM empWHERE job = 'CLERK';Ename Hired SAL PREVSAL------ --------- ----- -------SMITH 17-DEC-80 800 0JAMES 03-DEC-81 950 800MILLER 23-JAN-82 1300 950ADAMS 12-JAN-83 1100 1300

LEAD

LEAD ( value_expr [, offset] [, default] )  OVER ( [query_partition_clause] order_by_clause )

LEAD provides access to more than one row of a table at the same time without aself join. Given a series of rows returned from a query and a position of the cursor,

LEAD provides access to a row at a given physical offset beyond that position.

If you do not specify offset, then its default is 1. The optional default value is

returned if the offset goes beyond the scope of the table. If you do not specifydefault, then its default value is null.

The following example provides, for each employee in the EMP table, the hire date of the employee hired just after:

SELECT ename, hiredate,LEAD(hiredate, 1)OVER (ORDER BY hiredate) AS NextHired 

FROM emp WHERE deptno = 30;

Ename Hired NEXTHIRED------ --------- ---------ALLEN 20-FEB-81 22-FEB-81WARD 22-FEB-81 01-MAY-81

BLAKE 01-MAY-81 08-SEP-81TURNER 08-SEP-81 28-SEP-81MARTIN 28-SEP-81 03-DEC-81JAMES 03-DEC-81 

Determine the First Value / Last Value of a Group

The FIRST_VALUE and LAST_VALUE functions allow you to select the first and last

rows from a group. These rows are especially valuable because they are often used

Page 13: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 13/16

as the baselines in calculations.

Example

The following example selects, for each employee in each department, the name of the employee with the lowest salary.

break on deptno skip 1

SELECT deptno, ename, sal,  FIRST_VALUE(ename)OVER (PARTITION BY deptno

ORDER BY sal ASC) AS MIN_SAL_HASFROM empORDER BY deptno, ename;

DEPTNO ENAME SAL MIN_SAL_HAS---------- ---------- ---------- -----------

10 CLARK 2450 MILLERKING 5000 MILLER

   MILLER   1300 MILLER

20 ADAMS 1100 SMITHFORD 3000 SMITHJONES 2975 SMITHSCOTT 3000 SMITH

  SMITH  800 SMITH

30 ALLEN 1600 JAMESBLAKE 2850 JAMES

  JAMES  950 JAMES

MARTIN 1250 JAMESTURNER 1500 JAMESWARD 1250 JAMES 

The following example selects, for each employee in each department, the name of the employee with the highest salary.

SELECT deptno, ename, sal,FIRST_VALUE(ename)OVER (PARTITION BY deptno

ORDER BY sal DESC) AS MAX_SAL_HASFROM empORDER BY deptno, ename;

DEPTNO ENAME SAL MAX_SAL_HAS---------- ---------- ---------- -----_-----

10 CLARK 2450 KING  KING  5000 KING

MILLER 1300 KING

20 ADAMS 1100 FORD  FORD  3000 FORD

Page 14: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 14/16

JONES 2975 FORDSCOTT 3000 FORDSMITH 800 FORD

30 ALLEN 1600 BLAKE

  BLAKE  2850 BLAKEJAMES 950 BLAKEMARTIN 1250 BLAKETURNER 1500 BLAKEWARD 1250 BLAKE 

The following example selects, for each employee in department 30 the name of theemployee with the lowest salary using an inline view

SELECT deptno, ename, sal,  FIRST_VALUE(ename)OVER (ORDER BY sal ASC) AS MIN_SAL_HAS

FROM (SELECT * FROM emp WHERE deptno = 30) 

DEPTNO ENAME SAL MIN_SAL_HAS---------- ---------- ---------- -----------

30 JAMES 950 JAMESMARTIN 1250 JAMESWARD 1250 JAMESTURNER 1500 JAMESALLEN 1600 JAMESBLAKE 2850 JAMES 

Crosstab or Pivot Queries

A crosstab query, sometimes known as a pivot query, groups your data in a

slightly different way from those we have seen hitherto. A crosstab query can beused to get a result with three rows (one for each project), with each row having

three columns (the first listing the projects and then one column for each year) --like this:

Project 2001 2002ID CHF CHF

-------------------------------100 123.00 234.50200 543.00 230.00300 238.00 120.50

Example

Let's say you want to show the top 3 salary earners in each department as columns.

The query needs to return exactly 1 row per department and the row would have 4columns. The DEPTNO, the name of the highest paid employee in the department,

the name of the next highest paid, and so on. Using analytic functions this almosteasy, without analytic functions this was virtually impossible.

SELECT deptno,

Page 15: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 15/16

MAX(DECODE(seq,1,ename,null)) first,MAX(DECODE(seq,2,ename,null)) second,MAX(DECODE(seq,3,ename,null)) third 

FROM (SELECT deptno, ename,row_number()

OVER (PARTITION BY deptnoORDER BY sal desc NULLS LAST) seq FROM emp)

 WHERE seq <= 3GROUP BY deptno/ 

DEPTNO FIRST SECOND THIRD---------- ---------- ---------- ----------

10 KING CLARK MILLER20 SCOTT FORD JONES30 BLAKE ALLEN TURNER 

Note the inner query, that assigned a sequence (RowNr) to each employee bydepartment number in order of salary.

SELECT deptno, ename, sal,row_number()OVER (PARTITION BY deptno

ORDER BY sal desc NULLS LAST) RowNrFROM emp;

DEPTNO ENAME SAL ROWNR---------- ---------- ---------- ----------

10 KING 5000 110 CLARK 2450 2

10 MILLER 1300 320 SCOTT 3000 120 FORD 3000 220 JONES 2975 320 ADAMS 1100 420 SMITH 800 530 BLAKE 2850 130 ALLEN 1600 230 TURNER 1500 330 WARD 1250 430 MARTIN 1250 530 JAMES 950 6 

The DECODE in the outer query keeps only rows with sequences 1, 2 or 3 andassigns them to the correct "column". The GROUP BY gets rid of the redundant rowsand we are left with our collapsed result. It may be easier to understand if you see

the resultset without the aggregate function MAX grouped by deptno.

SELECT deptno,DECODE(seq,1,ename,null) first,DECODE(seq,2,ename,null) second,DECODE(seq,3,ename,null) third 

FROM (SELECT deptno, ename,

Page 16: Analytic Functions in Oracle 8i and 9i

8/8/2019 Analytic Functions in Oracle 8i and 9i

http://slidepdf.com/reader/full/analytic-functions-in-oracle-8i-and-9i 16/16

row_number()OVER (PARTITION BY deptno

ORDER BY sal desc NULLS LAST) seq FROM emp)

 WHERE seq <= 3

DEPTNO FIRST SECOND THIRD---------- ---------- ---------- ----------

10 KING10 CLARK10 MILLER20 SCOTT20 FORD20 JONES30 BLAKE30 ALLEN30 TURNER 

The MAX aggregate function will be applied by the GROUP BY column DEPTNO. In

any given DEPTNO above only one row will have a non-null value for FIRST, theremaining rows in that group will always be NULL. The MAX function will pick out the

non-null row and keep that for us. Hence, the group by and MAX will collapse ourresultset, removing the NULL values from it and giving us what we want.

Conclusion

This new set of functionality holds some exiting possibilities. It opens up a whole

new way of looking at the data. It will remove a lot of procedural code and complexor inefficient queries that would have taken a long tome to develop, to achieve the

same result.

Links and Documents

Further articles about Analytic Functions can be found in:

o Oracle9i SQL Reference Release 1 (9.0.1)

o Oracle9i Database Concepts Release 1 (9.0.1)

o Oracle9i Data Warehousing Guide Release 1 (9.0.1)