Sie sind auf Seite 1von 39

AnalyticFunctionsinOracle

Contents
OverviewandIntroduction
HowAnalyticFunctionsWork
TheSyntax
Examples
CalculatearunningTotal
TopNQueries
Example1
Example2
Windows
RangeWindows
Computeaveragesalaryfordefinedrange
RowWindows
AccessingRowsAroundYourCurrentRow
LAG
LEAD
DeterminetheFirstValue/LastValueofaGroup
CrosstaborPivotQueries
ROLLUPandRANKExamples
CUBE
GroupingFunctions:
Grouping_ID
GROUP_ID
GroupingSETS
MoreExampleswithEMPTable
Overview
AnalyticFunctionsaredesignedtoaddresssuchproblemsas"Calculatearunningtotal",
"Findpercentageswithinagroup","TopNqueries","Computeamovingaverage"and
manymore.
MostoftheseproblemscanbesolvedusingstandardPL/SQL,howevertheperformanceis
oftennotwhatitshouldbe.
AnalyticFunctionsaddextensionstotheSQLlanguagethatnotonlymaketheseoperations
easiertocodetheymakethemfasterthancouldbeachievedwithpureSQLorPL/SQL.
HowAnalyticFunctionsWork?
Analyticfunctionscomputeanaggregatevaluebasedonagroupofrows.Theydifferfrom
aggregatefunctions(likeselectAVG(sal)fromemp)inthattheyreturnmultiplerowsfor
eachgroup.
Analyticfunctionsalsooperateonsubsetsofrows,similartoaggregatefunctionsinGROUP
BYqueries,buttheydonotreducethenumberofrowsreturnedbythequery.
Thegroupofrowsiscalledawindowandisdefinedbytheanalyticclause.Foreachrow,a
"sliding"windowofrowsisdefined.Thewindowdeterminestherangeofrowsusedto
performthecalculationsforthe"currentrow".Windowsizescanbebasedoneithera
physicalnumberofrowsoralogicalintervalsuchastime.

SelectMAX()OVER()
TheOVER()statementsignalsastartofanAnalyticfunction.Thatiswhatdifferentiatesan
AnalyticalFunctionfromaregularOracleSQLfunction
SelectMAX()OVER(partitionbyfield1).
TheportioningclauseisusedtosetupthegroupofdatathattheAnalyticfunctionwouldbe
appliedto.
SelectMAX()OVER(Partitionbyfieldorderby)
Orderbyspecifytheorderofthewindowinthegroupbystatement.TheOrderbyclauseisa
keywordintheOracleAnalyticsyntaxthatisrequirementforusingsomeAnalyticfunctions
Analyticfunctionsarethelastsetofoperationsperformedinaqueryexceptforthefinal
ORDERBYclause.AlljoinsandallWHERE,GROUPBY,andHAVINGclausesare
completedbeforetheanalyticfunctionsareprocessed.Therefore,analyticfunctionscan
appearonlyintheselectlistorORDERBYclause.
Example:
SELECTempno,deptno,sal,
AVG(sal)OVER(PARTITIONBYdeptno)ASavg_dept_sal
FROMemp;
EMPNODEPTNOSALAVG_DEPT_SAL

77821024502916.66667
78391050002916.66667
79341013002916.66667
75662029752175
79022030002175
78762011002175
7369208002175
77882030002175
75213012501566.66667
78443015001566.66667
74993016001566.66667
7900309501566.66667
76983028501566.66667
76543012501566.66667

ThistimeAVGisananalyticfunction,operatingonthegroupofrowsdefinedbythe
contentsoftheOVERclause.Thisgroupofrowsisknownasawindow,whichiswhy
analyticfunctionsaresometimesreferredtoaswindow[ing]functions.NoticehowtheAVG
functionisstillreportingthedepartmentalaverage,likeitdidintheGROUPBYquery,but
theresultispresentineachrow,ratherthanreducingthetotalnumberofrowsreturned.This
isbecauseanalyticfunctionsareperformedonaresultsetafteralljoin,WHERE,GROUP
BYandHAVINGclausesarecomplete,butbeforethefinalORDERBYoperationis
performed.
TheSyntax
Therearesomevariationsinthesyntaxoftheindividualanalyticfunctions,butthebasic
syntaxforananalyticfunctionisasfollows.
analytic_function([arguments])OVER(analytic_clause)

Theanalytic_clausebreaksdownintothefollowingoptionalelements.

[query_partition_clause][order_by_clause[windowing_clause]]

Thesubelementsoftheanalytic_clauseeachhavetheirownsyntaxdiagrams.Ratherthan
repeatthesyntaxdiagrams,thefollowingsectionsdescribewhateachsectionofthe
analytic_clauseisusedfor.
SohereistheFULLsentence:
AnalyticFunction(<Argument>,<Argument>,...)
OVER(
<QueryPartitionClause>
<OrderByClause>
<WindowingClause>
)

AnalyticFunctions
Specifythenameofananalyticfunction,Oracleactuallyprovidesmanyanalytic
functionssuchasAVG,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.
Arguments
Analyticfunctionstake0to3arguments.
QueryPartitionClause
ThePARTITIONBYclauselogicallybreaksasingleresultsetintoNgroups,
accordingtothecriteriasetbythepartitionexpressions.Thewords"partition"and
"group"areusedsynonymouslyhere.Theanalyticfunctionsareappliedtoeachgroup
independently,theyareresetforeachgroup.Ifthequery_partition_clauseisomitted,
thewholeresultsetistreatedasasinglepartition.
Example:ThefollowingqueryusesanemptyOVERclause,sotheaveragepresented
isbasedonalltherowsoftheresultset.
SELECTempno,deptno,sal,
AVG(sal)OVER()ASavg_sal
FROMemp;
EMPNODEPTNOSALAVG_SAL

7369208002073.21429
74993016002073.21429
75213012502073.21429
75662029752073.21429
76543012502073.21429
76983028502073.21429
77821024502073.21429
77882030002073.21429
78391050002073.21429
78443015002073.21429
78762011002073.21429
7900309502073.21429
79022030002073.21429
79341013002073.21429

IfwechangetheOVERclausetoincludeaquery_partition_clausebasedonthe
department,theaveragespresentedarespecificallyforthedepartmenttheemployee
belongstoo.
SELECTempno,deptno,sal,
AVG(sal)OVER(PARTITIONBYdeptno)ASavg_dept_sal
FROMemp;
EMPNODEPTNOSALAVG_DEPT_SAL

77821024502916.66667
78391050002916.66667
79341013002916.66667
75662029752175
79022030002175
78762011002175
7369208002175
77882030002175
75213012501566.66667
78443015001566.66667
74993016001566.66667
7900309501566.66667
76983028501566.66667
76543012501566.66667

OrderByClause
Theorder_by_clauseisusedtoorderrows,orsiblings,withinapartition.Soifan
analyticfunctionissensitivetotheorderofthesiblingsinapartitionyoushould
includeanorder_by_clause.ThefollowingqueryusestheFIRST_VALUEfunctionto
returnthefirstsalaryreportedineachdepartment.Noticewehavepartitionedthe
resultsetbythedepartment,butthereisnoorder_by_clause.
SELECTempno,deptno,sal,
FIRST_VALUE(salIGNORENULLS)OVER(PARTITIONBYdeptno)AS
first_sal_in_dept
FROMemp;
EMPNODEPTNOSALFIRST_SAL_IN_DEPT

77821024502450
78391050002450
79341013002450
75662029752975
79022030002975
78762011002975
7369208002975
77882030002975
75213012501250
78443015001250
74993016001250
7900309501250
76983028501250
76543012501250

NowcomparethevaluesoftheFIRST_SAL_IN_DEPTcolumnwhenweincludean
order_by_clausetoorderthesiblingsbyascendingsalary.

SELECTempno,deptno,sal,
FIRST_VALUE(salIGNORENULLS)OVER(PARTITIONBYdeptnoORDERBYsal
ASCNULLSLAST)ASfirst_val_in_dept
FROMemp;
EMPNODEPTNOSALFIRST_VAL_IN_DEPT

79341013001300
77821024501300
78391050001300
736920800800
7876201100800
7566202975800
7788203000800
7902203000800
790030950950
7654301250950
7521301250950
7844301500950
7499301600950
7698302850950

Inthiscasethe"ASCNULLSLAST"keywordsareunnecessaryasASCisthedefault
foranorder_by_clauseandNULLSLASTisthedefaultforASCorders.When
orderingbyDESC,thedefaultisNULLSFIRST.
Itisimportanttounderstandhowtheorder_by_clauseaffectsdisplayorder.The
order_by_clauseisguaranteedtoaffecttheorderoftherowsastheyareprocessedby
theanalyticfunction,butitmaynotalwaysaffectthedisplayorder.Asaresult,you
mustalwaysuseaconventionalORDERBYclauseinthequeryifdisplayorderis
important.Donotrelyonanyimplicitorderingdonebytheanalyticfunction.
Remember,theconventionalORDERBYclauseisperformedaftertheanalytic
processing,soitwillalwaystakeprecedence.
WindowingClause
Thewindowing_clausegivessomeanalyticfunctionsafurtherdegreeofcontrolover
thiswindowwithinthecurrentpartition.Thewindowing_clauseisanextensionofthe
order_by_clauseandassuch,itcanonlybeusedifanorder_by_clauseispresent.The
windowing_clausehastwobasicforms.
RANGEBETWEENstart_pointANDend_point
ROWSBETWEENstart_pointANDend_point
Possiblevaluesfor"start_point"and"end_point"are:
UNBOUNDEDPRECEDING:Thewindowstartsatthefirstrowofthe
partition.Onlyavailableforstartpoints.
UNBOUNDEDFOLLOWING:Thewindowendsatthelastrowofthe
partition.ONlyavailableforendpoints.
CURRENTROW:Thewindowstartsorendsatthecurrentrow.Canbeused
asstartorendpoint.
value_exprPRECEDING:Anphysicalorlogicaloffsetbeforethecurrentrow
usingaconstantorexpressionthatevaluatestoapositivenumericalvalue.
WhenusedwithRANGE,itcanalsobeanintervalliteraliftheorder_by_clause

usesaDATEcolumn.
value_exprFOLLOWING:Asabove,butanoffsetafterthecurrentrow.
Foranalyticfunctionsthatsupportthewindowing_clause,thedefaultactionis
"RANGEBETWEENUNBOUNDEDPRECEDINGANDCURRENTROW".The
followingqueryissimilartooneusedpreviouslytoreporttheemployeesalaryand
averagedepartmentsalary,butnowwehaveincludedanorder_by_clausesowealso
getthedefaultwindowing_clause.Noticehowtheaveragesalaryisnowcalculated
usingonlytheemployeesfromthesamedepartmentuptoandincludingthecurrent
row.
SELECTempno,deptno,sal,
AVG(sal)OVER(PARTITIONBYdeptnoORDERBYsal)ASavg_dept_sal_sofar
FROMemp;
EMPNODEPTNOSALAVG_DEPT_SAL_SOFAR

79341013001300
77821024501875
78391050002916.66667
736920800800
7876201100950
75662029751625
77882030002175
79022030002175
790030950950
76543012501150
75213012501150
78443015001237.5
74993016001310
76983028501566.66667

Thefollowingqueryshowsonemethodforaccessingdatafrompreviousand
followingrowswithinthecurrentrowusingthewindowing_clause.Thiscanalsobe
accomplishedwithLAGandLEAD.
SELECTempno,deptno,sal,
FIRST_VALUE(sal)OVER(ORDERBYsalROWSBETWEEN1PRECEDINGAND
CURRENTROW)ASprevious_sal,
LAST_VALUE(sal)OVER(ORDERBYsalROWSBETWEENCURRENTROWAND1
FOLLOWING)ASnext_sal
FROMemp;
EMPNODEPTNOSALPREVIOUS_SALNEXT_SAL

736920800800950
7900309508001100
78762011009501250
752130125011001250
765430125012501300
793410130012501500
784430150013001600
749930160015002450
778210245016002850
769830285024502975
756620297528503000
778820300029753000
790220300030005000
783910500030005000

Moreinformationonwindowscanbefoundhere.
AnalyticFunctionExamples
SimpleExample
Select*from(Selectcust_name,sum(clm_amt)clm_amt
fromcustomer
groupbycust_name
orderbyclm_amtdescdesc)v
)
andrownum<11;

SimpleExampleresult
CUST_NAMECLM_AMT

XYZ100,000,000
LexusCorp80,000,000
FirstAmerica60,000,000
Yelp78,000,000
ABC75,000,000
OmegaInt.74,000,000
SCorp70,000,000
Acme25,000,000
SunEnterprise23,000,000
Filmstudio17,000,000

AnalyticVersion
selectcust_name,SUM(clm_amt)OVER(partitionbycust_name)clm_amt;

Inthefollowingexamplewe'llshowGROUPINGSETS(Listing1),GROUPBYROLLUP(Listing2),andGROUP
BYCUBE(Listing3)toseewhatwegetwitheach.We'llusethestandardSCOTT.EMPtabletodothis.The
firstquerywillshowusthesumofsalariesbyDEPTNOandbyJOB.WeneedtousetheGROUPING_ID
functiontodeterminewhataggregationeachrowrepresents.Itmightnotbeobviouswhywewouldneed
thisingeneralfromtheexample,butconsiderwhatwouldhappenifDEPTNOorJOBwereNULLABLE.There
wouldbenowaytodistinguishthedetailrowfromtheaggregatedrow.
TheGROUPING_IDfunctionreturnsa0or1whengivenasinglecolumn.(Inthiscase,itworksjustlikethe
GROUPINGfunction.)Ifthereturnvalueis0,indicatingadetailrecordvalueforthatparticularcolumn,
thenthecolumninquestionwasnotaggregatedover(wasnotcollapsed).Ifthefunctionreturns1,then
thecolumninquestionwasaggregatedoveranyaggregatesintheSELECTlistwouldhavebeen
computedoverthatentirecolumn'ssetofvalues.GROUPING_IDdiffersfromGROUPING,inthatyoucansend
alistofcolumnsandtheGROUPING_IDfunctionwilltreatthelistasbitsandreturnadecimalnumber.That
meansthatthecalltoGROUPING_ID(a,b,c)mightreturnanynumberbetween0and7,becausedifferent
0/1combinationsarereturned.Giventhatfact,wecanuseaCASEstatementinthequerytoseeiftherow
isadetailrowforDEPTNO,forJOB,forneither,orforboth.
UsingGROUPINGSETSinListing1,weaskedforGROUPBYonlyonDEPTNOandthenonlyonJOB.So,that
onequerywaslikerunningthefollowingquery
selectdeptno,null,sum(sal)
fromempgroupbydeptno
unionall
selectnull,job,sum(sal)
fromempgroupbyjob;

CodeListing1:UsingGROUPING_IDwithGROUPINGSETS
selectdeptno,job,sum(sal),
grouping_id(deptno)gid_d,
grouping_id(job)gid_j,
grouping_id(deptno,job)gid_dj,
bin_to_num(grouping_id(deptno),grouping_id(job))b2n,
casewhengrouping_id(deptno,job)=0
then'Dtlboth'
whengrouping_id(deptno,job)=1
then'Aggoverjob'
whengrouping_id(deptno,job)=2
then'Aggoverdeptno'
whengrouping_id(deptno,job)=3
then'Aggoverboth'
endwhat
fromemp
groupbygroupingsets((deptno),(job));

DEPTNO JOBSUM(SAL)
GID_DGID_JGID_DJB2NWHAT
____________________________________________________________________________
10

8750
0
1
1 1Aggoverjob
20

0875
0
1
1 1Aggoverjob
30

9400
0
1
1 1Aggoverjob

ANALYST
6000
1
0
2 2Aggoverdeptno
CLERK
4150
1
0
2 2Aggoverdeptno
MANAGER
8275
1
0
22Aggoverdeptno
PRESIDENT 5000
1
0
2 2Aggoverdeptno
SALESMAN
5600
1
0
2 2Aggoverdeptno

...butwithouthavingtomaketwopassesontheEMPtable,aswouldbethecasewiththeUNIONALL.
InlookingatthecolumnsinvolvedinthequeryinListing1,wecanseethatthefunction
GROUPING(column_name)showsuswhenacolumnisaggregatedoverorpreservedasadetailrecord.
WhenGROUPING(deptno)=0,DEPTNOispreservedintheoutput.Whenitis1,itisaggregatedover.
However,wehavetwocolumnsinthissetweareaggregatingby,foratotaloffourpossible0/1
combinations.(Inthisquery,onlytwoarepossible.)UsingtheGROUPING_IDfunctiononthisvectorof
columns,wecaneasilyseewhateachrowrepresents.I'vealsoincludedthealternative,moreverbose
waytoaccomplishthistheBIN_TO_NUM()function,towhichwecansendalistof0sand1sandgetback
adecimalnumberaswell.I'mprettysureyou'llagreethatGROUPING_ID(c1,c2,c3)iseasierthanthe
correspondingBIN_TO_NUMcallwiththreeGROUPINGcalls.
InListing2,wetakealookatGROUPBYROLLUP.ArollupbythetwocolumnsDEPTNOandJOBwill
produce
1. DetailrecordsbyDEPTNO,JOB(sumofSALforeachDEPTNO/JOBcombination).
2. AsummaryrecordforeachDEPTNOoverJOB(likeasubtotal).
3. AsummaryrecordoverDEPTNOandJOBasingleaggregatefortheentireresult.Listing2shows
thequeryandtheresults.
CodeListing2:UsingGROUPING_IDwithGROUPBYROLLUP
selectdeptno,job,sum(sal),
grouping_id(deptno)gid_d,
grouping_id(job)gid_j,
casewhengrouping_id(deptno,job)=0
then'Dtlboth'

whengrouping_id(deptno,job)=1
then'Aggoverjob'
whengrouping_id(deptno,job)=2
then'Aggoverdeptno'
whengrouping_id(deptno,job)=3
then'Aggoverboth'
endwhat
fromemp
groupbyrollup(deptno,job);

DEPTNO JOB SUM(SAL)GID_D


GID_J WHAT
______________________________________________________________
10
CLERK1300 0
0
Dtlboth
10
MANAGER
2450 0
0
Dtlboth
10
PRESIDENT
5000 0
0
Dtlboth
10

8750 0
1
Aggoverjob
20
CLERK1900 0
0
Dtlboth
20
ANALYST
6000 0
0
Dtlboth
20
MANAGER
2975 0
0
Dtlboth
20

10875 0
1
Aggoverjob
30
CLERK950 0
0
Dtlboth
30
MANAGER
2850 0
0
Dtlboth
30
SALESMAN
5600 0
0
Dtlboth
30

9400 0
1
Aggoverjob

29025 1
1
Aggoverboth

Arollupissortoflikearunningtotalreport,andGROUPING_IDtellsuswhentherollupshappened.Sothe
dataissortedbyDEPTNO,JOB,andwehavesubtotalsbyDEPTNO(aggregatedoverJOB)andbyDEPTNO,JOB
(aggregatedoverboth)alongwiththedetailsbyDEPTNO/JOB.
AsyoucanseeinListing2,theGROUPING_IDfunctionwasusefulintellinguswhenweweredealingwith
arolleduprecordandthelevelofdetailwecouldexpectinthatrecord.
Last,we'lllookatGROUPBYCUBE.CUBEissimilartoROLLUP,inthatyougetthesamethreerecordtypesas
showninListing2butalsogetallpossibleaggregations.CUBEgroupingbyDEPTNOandJOBwillgiveyou
recordsbyallofthefollowing:
1. DEPTNOandJOB
2. DEPTNOoverJOB
3. JOBoverDEPTNO
4. Asingletotalaggregate
Yougeteverypossibleaggregate.Listing3showsthesyntaxandoutputandhowtousetheGROUPING_ID
functiontoseewhatthelevelofdetailisforeachrow.ItisinterestingtonotethatGROUPBYCUBE
producesasupersetoftherowsweobservedinthefirstquery(inListing1).YoucoulduseGROUPING_ID
withCUBEtogeneratethesameresultsetastheoriginalgroupingsetsquery.Thatis,adding
having(grouping_id(deptno,job)=2
or(grouping_id(deptno,job)=1

...totheGROUPBYCUBEquerywouldcauseittobethelogicalequivalentoftheGROUPINGSETSquery.
Butyoushouldn'tdothat!Ifyouneedonlysomeoftheaggregates,useGROUPINGSETStogetjustthe
onesyouneedcomputedandavoidcomputingtheothersaltogether.Itwouldbefairtosaythat
GROUPING_IDdoesn'tavoidmultiplegroupingfunctionsbutGROUPINGSETSdoes.However,GROUPING_ID
playsanimportantroleinseeingwhatdataiswhat.

CodeListing3:UsingGROUPING_IDwithGROUPBYCUBE
selectdeptno,job,sum(sal),
grouping_id(deptno)gid_d,
grouping_id(job)gid_j,
casewhengrouping_id(deptno,job)=0
then'Dtlboth'
whengrouping_id(deptno,job)=1
then'Aggoverjob'
whengrouping_id(deptno,job)=2
then'Aggoverdeptno'
whengrouping_id(deptno,job)=3
then'Aggoverboth'
endwhat
fromemp
groupbycube(deptno,job)
orderbygrouping_id(deptno,job);

DEPTNO JOBSUM(SAL)
GID_D GID_JWHAT
__________________________________________________________________
10
CLERK
1300
0
0
Dtlboth
10
MANAGER
2450
0
0
Dtlboth
10
PRESIDENT 5000
0
0
Dtlboth
20
CLERK
1900
0
0
Dtlboth
30
CLERK
950
0
0
Dtlboth
30
SALESMAN
5600
0
0
Dtlboth
30
MANAGER
2850
0
0
Dtlboth
20
MANAGER
2975
0
0
Dtlboth
20
ANALYST
6000
0
0
Dtlboth
10

8750
0
1
Aggoverjob
20

10875
0
1
Aggoverjob
30

9400
0
1
Aggoverjob

CLERK
4150
1
0
Aggoverdeptno

ANALYST
6000
1
0
Aggoverdeptno

MANAGER
8275
1
0
Aggoverdeptno

PRESIDENT 5000
1
0
Aggoverdeptno

SALESMAN
5600
1
0
Aggoverdeptno

29025
1
1
Aggoverboth

Example:CalculatearunningTotal
Thisexampleshowsthecumulativesalarywithinadepartementrowbyrow,witheachrow
includingasummationofthepriorrowssalary.
setautotracetraceonlyexplain
breakondeptnoskip1
columnenameformatA6
columndeptnoformat999
columnsalformat99999
columnseqformat999
SELECTename"Ename",deptno"Deptno",sal"Sal",
SUM(sal)OVER(ORDERBYdeptno,ename)"RunningTotal",
SUM(SAL)OVER(PARTITIONBYdeptno
ORDERBYename)"DeptTotal",
ROW_NUMBER()

OVER(PARTITIONBYdeptnoORDERBYENAME)"Seq"
FROMemp
ORDERBYdeptno,ename
/
EnameDeptnoSalRunningTotalDeptTotalSeq

CLARK102450245024501
KING5000745074502
MILLER1300875087503
ADAMS201100985011001
FORD30001285041002
JONES29751582570753
SCOTT300018825100754
SMITH80019625108755
ALLEN3016002122516001
BLAKE28502407544502
JAMES9502502554003
MARTIN12502627566504
TURNER15002777581505
WARD12502902594006
ExecutionPlan

0SELECTSTATEMENTOptimizer=CHOOSE
10WINDOW(SORT)
21TABLEACCESS(FULL)OF'EMP'
Statistics

0recursivecalls
0dbblockgets
3consistentgets
0physicalreads
0redosize
1658bytessentviaSQL*Nettoclient
503bytesreceivedviaSQL*Netfromclient
2SQL*Netroundtripsto/fromclient
1sorts(memory)
0sorts(disk)
14rowsprocessed

Theexampleshowshowtocalculatea"RunningTotal"fortheentirequery.Thisisdone
usingtheentireorderedresultset,viaSUM(sal)OVER(ORDERBYdeptno,ename).
Further,wewereabletocomputearunningtotalwithineachdepartment,atotalthat
wouldberesetatthebeginningofthenextdepartment.ThePARTITIONBYdeptnointhat
SUM(sal)causedthistohappen,apartitioningclausewasspecifiedinthequeryinorderto
breakthedataupintogroups.
TheROW_NUMBER()functionisusedtosequentiallynumbertherowsreturnedineach
group,accordingtoourorderingcriteria(a"Seq"columnwasaddedtoinordertodisplay
thisposition).
Theexecutionplanshows,thatthewholequeryisverywellperformedwithonly3
consistentgets,thiscanneverbeaccomplishedwithstandardSQLorevenPL/SQL.
TopNQueries

HowcanwegettheTopNrecordsbysomesetoffields?
Priortohavingaccesstotheseanalyticfunctions,questionsofthisnaturewereextremely
difficulttoanswer.TherearesomeproblemswithTopNquerieshowevermostlyinthe
waypeoplephrasethem.Itissomethingtobecarefulaboutwhendesigningreports.
Considerthisseeminglysensiblerequest:
Iwouldlikethetopthreepaidsalesrepsbydepartment
Usingthe"traditionalapproachyoucanperform:
select*from
(your_query)
whererownum<=10;

Theproblemwiththisquestionisthatitisambiguousbecauseofrepeatedvalues,there
mightbefourpeoplewhoallmakethesamesalary,whatshouldwedothen?
Let'slookatthreeexamples,allusethewellknowntableEMP.
Example1
Let'slookatwhatROW_NUMBERcando.Hereisanexamplequeryusing
ROW_NUMBERtoassignanincreasingnumbertoeachrowintheEMPtableaftersorting
bySALDESC:
selectename,sal,
row_number()over(orderbysaldesc)rn
fromemp
orderbysaldesc;
ENAMESALRN

KING50001
FORD30002
SCOTT30003
JONES29754
.
.
.
JAMES95013
SMITH80014

IcanapplyapredicatetoROW_NUMBERafteritisassigned.Forexample
select*from(selectename,sal,
row_number()over(orderbysaldesc)rn
fromemp)
wherern<=3
orderbysaldesc;
ENAMESALRN

KING50001
SCOTT30002
FORD30003

So,thatdemonstrateshowtoperformatopnquerybyusingROW_NUMBERandalso
pointsoutageneralissuewithtopnqueries.Ifyoulookatthatresult,youseetworowswith
thevalue3000.Whatif,intheEMPtable,threepeople,insteadofjusttwo,hadasalaryof

3000?TheresultobtainedbytheabovequerywouldbeambiguousIwouldgetthree
records,buttherecordsIretrievedwouldbesomewhatrandom.Wewillanalyzethatonthe
example2:
AnotherExample:
Sortthesalespeoplebysalaryfromgreatesttoleast.Givethefirstthreerows.Ifthereare
lessthenthreepeopleinadepartment,thiswillreturnlessthanthreerecords.
setautotraceonexplain
breakondeptnoskip1
SELECT*FROM(SELECTdeptno,ename,sal,ROW_NUMBER()
OVER(PARTITIONBYdeptno
ORDERBYsalDESC)
Top3FROMemp)
WHERETop3<=3;
DEPTNOENAMESALTOP3

10KING50001
CLARK24502
MILLER13003
20SCOTT30001
FORD30002
JONES29753
30BLAKE28501
ALLEN16002
TURNER15003

Thisqueryworksbysortingeachpartition(orgroup,whichisthedeptno),inadescending
order,basedonthesalarycolumnandthenassigningasequentialrownumbertoeachrowin
thegroupasitisprocessed.TheuseofaWHEREclauseafterdoingthistogetjustthefirst
threerowsineachpartition.

Example2
Bearingthisinmind,Icanuseotheranalyticfunctionstoremovetheambiguityfrom
example1.Theywilldoso,buttheanalyticfunctionsmightreturnmorethannrows.Inmy
opinion,whentheattributeIorderbyisnotunique,Iwantmyquerytoreturnallofthe
relevantrecordsnotjustthefirstnarbitraryones.Tothatend,IcanusetheRANKand
DENSE_RANKanalyticfunctions.Let'stakealookatwhattheydo:
selectename,sal,
row_number()over(orderbysaldesc)rn,
rank()over(orderbysaldesc)rnk,
dense_rank()over(orderbysaldesc)drnk
fromemp
orderbysaldesc;
ENAMESALRNRNKDRNK

KING5000111

FORD3000222
SCOTT3000322
JONES2975443
BLAKE2850554
CLARK2450665
.
.
.

Themainthingstonoteherearethefollowing:
ROW_NUMBERassignscontiguous,uniquenumbersfrom1..Ntoaresultset.
RANKdoesnotassignuniquenumbersFORDandSCOTTtiedforsecondplace
nordoesitassigncontiguousnumbers.Norecordwasassignedthevalueof3,because
twopeopletiedforsecondplace,andnoonecameinthird,accordingtoRANK.
DENSE_RANK,likeRANK,doesnotassignuniquenumbers,butitdoesassign
contiguousnumbers.Eventhoughtworecordstiedforsecondplace,thereisathird
placerecord.
YoucanuseRANKandDENSE_RANKinthesamewayyouwoulduseROW_NUMBER
torestrictthenumberofrowsreturned,butobviouslyyou'llgetsubtlydifferentresults.For
example
select*from(selectename,sal,
dense_rank()over(orderbysaldesc)drnk
fromemp)
wheredrnk<=3
orderbysaldesc;
ENAMESALDRNK

KING50001
SCOTT30002
FORD30002
JONES29753

Thatqueryreturns"thesetofpeoplewhomakethetopthreesalaries,"whichislikelythe
desiredresult.GettingthefirstthreerecordsfromEMPaftersortingbySALisrather
arbitrary,becauseusingexactlythesamesetofdata,simplyinsertedindifferentorders,you
couldobservedifferentresultsetswithROW_NUMBER(becauseSALisnotunique).
UsingDENSE_RANK,however,Idon'tgetpreciselythreerecordsbut,instead,arepeatable
(deterministic)resultset.AndIsuspectthatIretrievethesettheenduserreallymeantto
retrievethesetofpeoplemakingthetopthreesalaries.

AnotherExample:
Givemethesetofsalespeoplewhomakethetop3salariesthatis,findthesetofdistinct
salaryamounts,sortthem,takethelargestthree,andgivemeeveryonewhomakesoneof
thosevalues.
SELECT*FROM(SELECTdeptno,ename,sal,

DENSE_RANK()OVER(PARTITIONBYdeptnoORDERBYsaldesc)
TopNFROMemp)
WHERETopN<=3
ORDERBYdeptno,salDESC;
DEPTNOENAMESALTOPN

10KING50001
CLARK24502
MILLER13003
20SCOTT30001<!
FORD30001<!
JONES29752
ADAMS11003
30BLAKE28501
ALLEN16002
30TURNER15003

HeretheDENSE_RANKfunctionwasusedtogetthetopthreesalaries.Weassignedthe
denseranktothesalarycolumnandsorteditinadescendingorder.
TheDENSE_RANKfunctioncomputestherankofarowinanorderedgroupofrows.The
ranksareconsecutiveintegersbeginningwith1.Thelargestrankvalueisthenumberof
uniquevaluesreturnedbythequery.Rankvaluesarenotskippedintheeventofties.Rows
withequalvaluesfortherankingcriteriareceivethesamerank.
TheDENSE_RANKfunctiondoesnotskipnumbersandwillassignthesamenumberto
thoserowswiththesamevalue.Hence,aftertheresultsetisbuiltintheinlineview,wecan
simplyselectalloftherowswithadenserankofthreeorless,thisgivesuseveryonewho
makesthetopthreesalariesbydepartmentnumber.
Windows
Thewindowingclausegivesusawaytodefineaslidingoranchoredwindowofdata,on
whichtheanalyticfunctionwilloperate,withinagroup.Thedefaultwindowisananchored
windowthatsimplystartsatthefirstrowofagroupancontinuestothecurrentrow.
Wecansetupwindowsbasedontwocriteria:RANGESofdatavaluesorROWSoffset
fromthecurrentrow.Itcanbesaid,thattheexistanceofanORDERBYinananalytic
functionwilladdadefaultwindowclauseofRANGEUNBOUNDEDPRECEDING.That
saystogetallrowsinourpartitionthatcamebeforeusasspecifiedbytheORDERBY
clause.
Let'slookatanexamplewithaslidingwindowwithinagroupandcomputethesumofthe
currentrow'sSALcolumnplustheprevious2rowsinthatgroup.Ifweneedareportthat
showsthesumofthecurrentemployee'ssalarywiththeprecedingtwosalarieswithina
departement,itwouldlooklikethis.
breakondeptnoskip1
columnenameformatA6
columndeptnoformat999
columnsalformat99999
SELECTdeptno"Deptno",ename"Ename",sal"Sal",
SUM(SAL)OVER(PARTITIONBYdeptno
ORDERBYename
ROWS2PRECEDING)"SlidingTotal"

FROMemp
ORDERBYdeptno,ename;
DeptnoEnameSalSlidingTotal

10CLARK24502450
KING50007450
MILLER13008750
20ADAMS11001100
FORD30004100
JONES29757075^
SCOTT30008975|
SMITH8006775\SlidingWindow
30ALLEN16001600
BLAKE28504450
JAMES9505400
MARTIN12505050
TURNER15003700
WARD12504000

ThepartitionclausemakestheSUM(sal)becomputedwithineachdepartment,independent
oftheothergroups.TtheSUM(sal)is'reset'asthedepartmentchanges.TheORDERBY
ENAMEclausesortsthedatawithineachdepartmentbyENAMEthisallowsthewindow
clause:ROWS2PRECEDING,toaccessthe2rowspriortothecurrentrowinagroup
inordertosumthesalaries.
Forexample,ifyounotetheSLIDINGTOTALvalueforSMITHis6775,whichisthe
sumof800,3000,and2975.ThatwassimplySMITH'srowplusthesalaryfromthe
precedingtworowsinthewindow.
RangeWindows
RangewindowscollectrowstogetherbasedonaWHEREclause.IfIsay'range5preceding
'forexample,thiswillgenerateaslidingwindowthathasthesetofallprecedingrowsinthe
groupsuchthattheyarewithin5unitsofthecurrentrow.Theseunitsmayeitherbenumeric
comparisonsordatecomparisonsanditisnotvalidtouseRANGEwithdatatypesotherthan
numbersanddates.
Example
Counttheemployeeswhichwherehiredwithinthelast100daysprecedingtheownhiredate.
Therangewindowgoesback100daysfromthecurrentrow'shiredateandthencountsthe
rowswithinthisrange.Thesolutionisttousethefollowingwindowspecification:
COUNT(*)OVER(ORDERBYhiredateASCRANGE100PRECEDING)
columnenameheading"Name"formata8
columnhiredateheading"Hired"formata10
columnhiredate_preheading"Hired100"formata10
columncntheading"Cnt"format99
SELECTename,hiredate,hiredate100hiredate_pre,
COUNT(*)OVER(ORDERBYhiredateASC
RANGE100PRECEDING)cnt
FROMemp
ORDERBYhiredateASC;

NameHiredHired100Cnt

SMITH17DEC8008SEP801
ALLEN20FEB8112NOV802
WARD22FEB8114NOV803
JONES02APR8123DEC803
BLAKE01MAY8121JAN814
CLARK09JUN8101MAR813
TURNER08SEP8131MAY812
MARTIN28SEP8120JUN812
KING17NOV8109AUG813
JAMES03DEC8125AUG815
FORD03DEC8125AUG815
MILLER23JAN8215OCT814
SCOTT09DEC8231AUG821
ADAMS12JAN8304OCT822

WeorderedthesinglepartitionbyhiredateASC.Ifwelookforexampleattherowfor
CLARKwecanseethathishiredatewas09JUN81,and100dayspriortothatisthedate
01MAR81.Ifwelookwhowashiredbetween01MAR81and09JUN81,wefind
JONES(hired:02APR81)andBLAKE(hired:01MAY81).Thisare3rowsincludingthe
currentrow,thisiswhatweseeinthecolumn"Cnt"ofCLARK'srow.
Computeaveragesalaryfordefinedrange
Asanexample,computetheaveragesalaryofpeoplehiredwithin100daysbeforeforeach
employee.Thequerylookslikethis:
columnenameheading"Name"formata8
columnhiredateheading"Hired"formata10
columnhiredate_preheading"Hired100"formata10
columnavg_salheading"Avg100"format999999
SELECTename,hiredate,sal,
AVG(sal)OVER(ORDERBYhiredateASC
RANGE100PRECEDING)avg_sal
FROMemp
ORDERBYhiredateASC;
NameHiredSALAvg100

SMITH17DEC80800800
ALLEN20FEB8116001200
WARD22FEB8112501217
JONES02APR8129751942
BLAKE01MAY8128502169
CLARK09JUN8124502758
TURNER08SEP8115001975
MARTIN28SEP8112501375
KING17NOV8150002583
JAMES03DEC819502340
FORD03DEC8130002340
MILLER23JAN8213002563
SCOTT09DEC8230003000
ADAMS12JAN8311002050

LookatCLARKagain,sinceweunderstandhisrangewindowwithinthegroup.Wecansee
thattheaveragesalaryof2758isequalto(2975+2850+2450)/3.Thisistheaverageofthe

salariesforCLARKandtherowsprecedingCLARK,thoseofJONESandBLAKE.The
datamustbesortedinascendingorder.
RowWindows
RowWindowsarephysicalunitsphysicalnumberofrows,toincludeinthewindow.For
exampleyoucancalculatetheaveragesalaryofagivenrecordwiththe(upto5)employees
hiredbeforethemorafterthemasfollows:
setnumformat9999
SELECTename,hiredate,sal,
AVG(sal)
OVER(ORDERBYhiredateASCROWS5PRECEDING)AvgAsc,
COUNT(*)
OVER(ORDERBYhiredateASCROWS5PRECEDING)CntAsc,
AVG(sal)
OVER(ORDERBYhiredateDESCROWS5PRECEDING)AvgDes,
COUNT(*)
OVER(ORDERBYhiredateDESCROWS5PRECEDING)CntDes
FROMemp
ORDERBYhiredate;
ENAMEHIREDATESALAVGASCCNTASCAVGDESCNTDES

SMITH17DEC80800800119886
ALLEN20FEB8116001200221046
WARD22FEB8112501217320466
JONES02APR8129751656426716
BLAKE01MAY8128501895526756
CLARK09JUN8124501988623586
TURNER08SEP8115002104621676
MARTIN28SEP8112502046624176
KING17NOV8150002671623926
JAMES03DEC819502333615884
FORD03DEC8130002358618705
MILLER23JAN8213002167618003
SCOTT09DEC8230002417620502
ADAMS12JAN8311002392611001

Thewindowconsistofupto6rows,thecurrentrowandfiverows"infrontof"thisrow,
where"infrontof"isdefinedbytheORDERBYclause.WithROWpartitions,wedonot
havethelimitationofRANGEpartitionthedatamaybeofanytypeandtheorderbymay
includemanycolumns.Notice,thatweselectedoutaCOUNT(*)aswell.Thisisusefuljust
todemonstratehowmanyrowswentintomakingupagivenaverage.Wecanseeclearly
thatforALLEN'srecord,theaveragesalarycomputationforpeoplehiredbeforehimused
only2recordswhereasthecomputationforsalariesofpeoplehiredafterhimused6.
AccessingRowsAroundYourCurrentRow
Frequentlyyouwanttoaccessdatanotonlyfromthecurrentrowbutthecurrentrow"in
frontof"or"behind"them.Forexample,let'ssayyouneedareportthatshows,by
departmentalloftheemployeestheirhiredatehowmanydaysbeforewasthelasthire
howmanydaysafterwasthenexthire.
UsingstraightSQLthisquerywouldbedifficulttowrite.Notonlythatbutitsperformance
wouldonceagaindefinitelybequestionable.TheapproachItypicallytookinthepastwas
eitherto"selectaselect"orwriteaPL/SQLfunctionthatwouldtakesomedatafromthe

currentrowand"find"thepreviousandnextrowsdata.Thisworked,butintroducelarge
overheadintoboththedevelopmentofthequeryandtheruntimeexecutionofthequery.
Usinganalyticfunctions,thisiseasyandefficienttodo.
setechoon
columndeptnoformat99headingDep
columnenameformata6headingEname
columnhiredateheadingHired
columnlast_hireheadingLastHired
columndays_lastheadingDaysLast
columnnext_hireheadingNextHire
columndays_nextheadingNextDays
breakondeptnoskip1
SELECTdeptno,ename,hiredate,
LAG(hiredate,1,NULL)
OVER(PARTITIONBYdeptno
ORDERBYhiredate,ename)last_hire,
hiredateLAG(hiredate,1,NULL)
OVER(PARTITIONBYdeptno
ORDERBYhiredate,ename)days_last,
LEAD(hiredate,1,NULL)
OVER(PARTITIONBYdeptno
ORDERBYhiredate,ename)next_hire,
LEAD(hiredate,1,NULL)
OVER(PARTITIONBYdeptno
ORDERBYhiredate,ename)hiredatedays_next
FROMemp
ORDERBYdeptno,hiredate;
DepEnameHiredLastHiredDaysLastNextHireNextDays

10CLARK09JUN8117NOV81161
KING17NOV8109JUN8116123JAN8267
MILLER23JAN8217NOV8167
20SMITH17DEC8002APR81106
JONES02APR8117DEC8010603DEC81245
FORD03DEC8102APR8124509DEC82371
SCOTT09DEC8203DEC8137112JAN8334
ADAMS12JAN8309DEC8234
30ALLEN20FEB8122FEB812
WARD22FEB8120FEB81201MAY8168
BLAKE01MAY8122FEB816808SEP81130
TURNER08SEP8101MAY8113028SEP8120
MARTIN28SEP8108SEP812003DEC8166
JAMES03DEC8128SEP8166

TheLEADandLAGroutinescouldbeconsideredawayto"indexintoyourpartitioned
group".Usingthesefunctionsyoucanaccessanyindividualrow.Noticeforexampleinthe
aboveprintout,itshowsthattherecordforKINGincludesthedata(inboldredfont)from
thepriorrow(LASTHIRE)andthenextrow(NEXTHIRE).Wecanaccessthefieldsin
recordsprecedingorfollowingthecurrentrecordinanorderedpartitioneasily.
LAG
LAG(value_expr[,offset][,default])

OVER([query_partition_clause]order_by_clause)
LAGprovidesaccesstomorethanonerowofatableatthesametimewithoutaselfjoin.
Givenaseriesofrowsreturnedfromaqueryandapositionofthecursor,LAGprovides
accesstoarowatagivenphysicaloffsetpriortothatposition.Ifyoudonotspecifyoffset,
thenitsdefaultis1.Theoptionaldefaultvalueisreturnediftheoffsetgoesbeyondthescope
ofthewindow.Ifyoudonotspecifydefault,thenitsdefaultvalueisnull.Thefollowing
exampleprovides,foreachpersonintheEMPtable,thesalaryoftheemployeehiredjust
before:
SELECTename,hiredate,sal,
LAG(sal,1,0)OVER(ORDERBYhiredate)ASPrevSal
FROMemp
WHEREjob='CLERK';
EnameHiredSALPREVSAL

SMITH17DEC808000
JAMES03DEC81950800
MILLER23JAN821300950
ADAMS12JAN8311001300

LEAD
LEAD(value_expr[,offset][,default])
OVER([query_partition_clause]order_by_clause)
LEADprovidesaccesstomorethanonerowofatableatthesametimewithoutaselfjoin.
Givenaseriesofrowsreturnedfromaqueryandapositionofthecursor,LEADprovides
accesstoarowatagivenphysicaloffsetbeyondthatposition.Ifyoudonotspecifyoffset,
thenitsdefaultis1.Theoptionaldefaultvalueisreturnediftheoffsetgoesbeyondthescope
ofthetable.Ifyoudonotspecifydefault,thenitsdefaultvalueisnull.Thefollowing
exampleprovides,foreachemployeeintheEMPtable,thehiredateoftheemployeehired
justafter:
SELECTename,hiredate,
LEAD(hiredate,1)OVER(ORDERBYhiredate)ASNextHired
FROMempWHEREdeptno=30;
EnameHiredNEXTHIRED

ALLEN20FEB8122FEB81
WARD22FEB8101MAY81
BLAKE01MAY8108SEP81
TURNER08SEP8128SEP81
MARTIN28SEP8103DEC81
JAMES03DEC81

DeterminetheFirstValue/LastValueofaGroup
TheFIRST_VALUEandLAST_VALUEfunctionsallowyoutoselectthefirstandlast
rowsfromagroup.Theserowsareespeciallyvaluablebecausetheyareoftenusedasthe
baselinesincalculations.

Example
Thefollowingexampleselects,foreachemployeeineachdepartment,thenameofthe
employeewiththelowestsalary.
breakondeptnoskip1
SELECTdeptno,ename,sal,
FIRST_VALUE(ename)
OVER(PARTITIONBYdeptno
ORDERBYsalASC)ASMIN_SAL_HAS
FROMemp
ORDERBYdeptno,ename;
DEPTNOENAMESALMIN_SAL_HAS

10CLARK2450MILLER
KING5000MILLER
MILLER1300MILLER
20ADAMS1100SMITH
FORD3000SMITH
JONES2975SMITH
SCOTT3000SMITH
SMITH800SMITH
30ALLEN1600JAMES
BLAKE2850JAMES
JAMES950JAMES
MARTIN1250JAMES
TURNER1500JAMES
WARD1250JAMES

Thefollowingexampleselects,foreachemployeeineachdepartment,thenameofthe
employeewiththehighestsalary.
SELECTdeptno,ename,sal,
FIRST_VALUE(ename)
OVER(PARTITIONBYdeptno
ORDERBYsalDESC)ASMAX_SAL_HAS
FROMemp
ORDERBYdeptno,ename;
DEPTNOENAMESALMAX_SAL_HAS
_
10CLARK2450KING
KING5000KING
MILLER1300KING
20ADAMS1100FORD
FORD3000FORD
JONES2975FORD
SCOTT3000FORD
SMITH800FORD
30ALLEN1600BLAKE
BLAKE2850BLAKE
JAMES950BLAKE
MARTIN1250BLAKE
TURNER1500BLAKE
WARD1250BLAKE

Thefollowingexampleselects,foreachemployeeindepartment30thenameofthe
employeewiththelowestsalaryusinganinlineview
SELECTdeptno,ename,sal,
FIRST_VALUE(ename)
OVER(ORDERBYsalASC)ASMIN_SAL_HAS
FROM(SELECT*FROMempWHEREdeptno=30)
DEPTNOENAMESALMIN_SAL_HAS

30JAMES950JAMES
MARTIN1250JAMES
WARD1250JAMES
TURNER1500JAMES
ALLEN1600JAMES
BLAKE2850JAMES

CrosstaborPivotQueries
Acrosstabquery,sometimesknownasapivotquery,groupsyourdatainaslightly
differentwayfromthosewehaveseenhitherto.Acrosstabquerycanbeusedtogetaresult
withthreerows(oneforeachproject),witheachrowhavingthreecolumns(thefirstlisting
theprojectsandthenonecolumnforeachyear)likethis:
Project20012002
IDCHFCHF

100123.00234.50
200543.00230.00
300238.00120.50
Example:
Let'ssayyouwanttoshowthetop3salaryearnersineachdepartmentascolumns.The
queryneedstoreturnexactly1rowperdepartmentandtherowwouldhave4columns.The
DEPTNO,thenameofthehighestpaidemployeeinthedepartment,thenameofthenext
highestpaid,andsoon.Usinganalyticfunctionsthisalmosteasy,withoutanalyticfunctions
thiswasvirtuallyimpossible.
SELECTdeptno,
MAX(DECODE(seq,1,ename,null))first,
MAX(DECODE(seq,2,ename,null))second,
MAX(DECODE(seq,3,ename,null))third
FROM(SELECTdeptno,ename,
row_number()
OVER(PARTITIONBYdeptno
ORDERBYsaldescNULLSLAST)seq
FROMemp)
WHEREseq<=3
GROUPBYdeptno;
DEPTNOFIRSTSECONDTHIRD

10KINGCLARKMILLER
20SCOTTFORDJONES
30BLAKEALLENTURNER

Notetheinnerquery,thatassignedasequence(RowNr)toeachemployeebydepartment
numberinorderofsalary.
SELECTdeptno,ename,sal,
row_number()
OVER(PARTITIONBYdeptno
ORDERBYsaldescNULLSLAST)RowNr
FROMemp;
DEPTNOENAMESALROWNR

10KING50001
10CLARK24502
10MILLER13003
20SCOTT30001
20FORD30002
20JONES29753
20ADAMS11004
20SMITH8005
30BLAKE28501
30ALLEN16002
30TURNER15003
30WARD12504
30MARTIN12505
30JAMES9506

TheDECODEintheouterquerykeepsonlyrowswithsequences1,2or3andassignsthem
tothecorrect"column".TheGROUPBYgetsridoftheredundantrowsandweareleftwith
ourcollapsedresult.Itmaybeeasiertounderstandifyouseetheresultsetwithoutthe
aggregatefunctionMAXgroupedbydeptno.
SELECTdeptno,
DECODE(seq,1,ename,null)first,
DECODE(seq,2,ename,null)second,
DECODE(seq,3,ename,null)third
FROM(SELECTdeptno,ename,
row_number()
OVER(PARTITIONBYdeptno
ORDERBYsaldescNULLSLAST)seq
FROMemp)
WHEREseq<=3;
DEPTNOFIRSTSECONDTHIRD

10KING
10CLARK
10MILLER
20SCOTT
20FORD
20JONES
30BLAKE
30ALLEN
30TURNER

TheMAXaggregatefunctionwillbeappliedbytheGROUPBYcolumnDEPTNO.Inany
givenDEPTNOaboveonlyonerowwillhaveanonnullvalueforFIRST,theremaining
rowsinthatgroupwillalwaysbeNULL.TheMAXfunctionwillpickoutthenonnullrow
andkeepthatforus.Hence,thegroupbyandMAXwillcollapseourresultset,removingthe

NULLvaluesfromitandgivinguswhatwewant.
Anotherexample:
ReturndatafromEMPtableinHorizontalmode(PivotTable)
WiththeadditionofanalyticfunctionsinOracle8iandtheSYS_CONNECT_BY_PATH()functionin
Oracle9i,thisbecamesomethingrathereasilyinSQL.
Takethefollowingapproach:
1.PartitionthedatabyDEPTNOand,foreachDEPTNO,sortthedatabyENAME,andassigna
sequentialnumberbyusingtheROW_NUMBER()analyticfunction.
2.UseaCONNECTBYquery,startingwithROW_NUMBER()equalto1andconnectingthatrecordto
thesameDEPTNOvaluewithROW_NUMBER()equalto2,andsoon.So,eventuallyendupwitha
recordthatistheresultofconnecting1to2to3to4,andsoon,foreachDEPTNOvalue.
3.Selectjustthe"longestconnectbypath"foreachDEPTNOvaluethelongestconnectbypathfor
eachDEPTNOvaluewillhavealloftheENAMEvaluesgatheredtogether.
TheSYS_CONNECT_BY_PATH()functionwillreturnthelistofconcatenatedENAMEvalues.
Thequerylookslikethis:
selectdeptno,
max(sys_connect_by_path
(ename,''))scbp
from(selectdeptno,ename,
row_number()over
(partitionbydeptno
orderbyename)rn
fromemp
)
startwithrn=1
connectbypriorrn=rn1
andpriordeptno=deptno
groupbydeptno
orderbydeptno
/
DEPTNOSCBP

10CLARKKINGMILLER
20ADAMSFORDJONESSCOTT...
30ALLENBLAKEJAMESMARTIN...

ROLLUPandRANKExamples
Lookingforaquick,efficientwaytosummarizethedatastoredinyourdatabase?TheSQLROLLUP
andCUBEcommandsofferavaluabletoolforgainingsomequickanddirtyinsightintoyourdata.
ROLLUPandCUBEareSQLextensions.
Verhttp://orafaq.com/node/56
TheROLLUPoperationworksonasetofcolumnsyouwanttogroup.JustliketheGROUPBY
operationbutaggregatesasummaryrowforeachgroupofcolumnssuppliedinitsclause.Rollupgives
thesumontheaggregateitisusedasanaddontotheGROUPBYclause.Fromthemostdetailedtoa
grandtotalandhasthefollowingbasicsyntaxformatof:
GROUPBYROLLUP([columnsofinterestseparatedbycommas])

DDLtousewiththeexamples:
createtableEmployee(
IDVARCHAR2(4BYTE)NOTNULL,
First_NameVARCHAR2(10BYTE),
Last_NameVARCHAR2(10BYTE),
Start_DateDATE,
End_DateDATE,
SalaryNumber(8,2),
CityVARCHAR2(10BYTE),
DescriptionVARCHAR2(15BYTE)
)
/
preparedata
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('01','Jason','Martin',to_date('19960725','YYYYMMDD'),
to_date('20060725','YYYYMMDD'),1234.56,'Toronto','Programme
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('02','Alison','Mathews',to_date('19760321','YYYYMMDD'),
to_date('19860221','YYYYMMDD'),6661.78,'Vancouver','Tester');
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('03','James','Smith',to_date('19781212','YYYYMMDD'),
to_date('19900315','YYYYMMDD'),6544.78,'Vancouver','Tester');
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('04','Celia','Rice',to_date('19821024','YYYYMMDD'),
to_date('19990421','YYYYMMDD'),2344.78,'Vancouver','Manager')
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('05','Robert','Black',to_date('19840115','YYYYMMDD'),
to_date('19980808','YYYYMMDD'),2334.78,'Vancouver','Tester');
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('06','Linda','Green',to_date('19870730','YYYYMMDD'),
to_date('19960104','YYYYMMDD'),4322.78,'NewYork','Tester');
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('07','David','Larry',to_date('19901231','YYYYMMDD'),
to_date('19980212','YYYYMMDD'),7897.78,'NewYork','Manager')
insertintoEmployee(ID,First_Name,Last_Name,Start_Date,End_Date,Salary,City,Description)
values('08','James','Cat',to_date('19960917','YYYYMMDD'),
to_date('20020415','YYYYMMDD'),1232.78,'Vancouver','Tester');

displaydatainthetable
select*fromEmployee;
IDFIRST_NAMELAST_NAMESTART_DATEND_DATESALARYCITYDESCRIPTION

01JasonMartin25JUL9625JUL061234.56TorontoProgrammer
02AlisonMathews21MAR7621FEB866661.78VancouverTester
03JamesSmith12DEC7815MAR906544.78VancouverTester
04CeliaRice24OCT8221APR992344.78VancouverManager
05RobertBlack15JAN8408AUG982334.78VancouverTester
06LindaGreen30JUL8704JAN964322.78NewYorkTester
07DavidLarry31DEC9012FEB987897.78NewYorkManager
08JamesCat17SEP9615APR021232.78VancouverTester

Rollup:givethesumontheaggregateitisusedasanaddontotheGROUPBYclause.
SELECTcount(*),city
FROMemployee

GROUPBYROLLUP(city);
COUNT(*)CITY

2NewYork
1Toronto
5Vancouver
8

WithROLLUPandROW_NUMBERadded
SELECTROW_NUMBER()OVER(ORDERBYcity,description)rn,
count(*),city,description
FROMemployee
GROUPBYROLLUP(city,description);
RNCOUNT(*)CITYDESCRIPTION

11NewYorkManager
21NewYorkTester
32NewYork
41TorontoProgrammer
51Toronto
61VancouverManager
74VancouverTester
85Vancouver
98

TheROLLUPclauseextendsGROUPBYtoreturnarowcontainingasubtotalforeachgroupalong
withatotalforallgroups
PassingaSingleColumntoROLLUP
TheROLLUPclauseextendsGROUPBYtoreturnarowcontainingasubtotalforeachgroupalong
withatotalforallgroups.
SELECTcity,SUM(salary)
FROMemployee
GROUPBYcity;
CITYSUM(SALARY)

NewYork12220.56
Toronto1234.56
Vancouver19118.9

ThefollowingqueryrewritesthepreviousexampletouseROLLUP.
SELECTcity,SUM(salary)
FROMemployee
GROUPBYROLLUP(city);
CITYSUM(SALARY)

NewYork12220.56
Toronto1234.56
Vancouver19118.9
32574.02

ChangingthePositionofColumnsPassedtoROLLUP

SELECTcity,description,SUM(salary)
FROMemployee
GROUPBYROLLUP(city,description);
CITYDESCRIPTIONSUM(SALARY)

TorontoProgrammer1234.56
Toronto1234.56
NewYorkTester4322.78
NewYorkManager7897.78
NewYork12220.56
VancouverTester16774.12
VancouverManager2344.78
Vancouver19118.9
32574.02
SELECTcity,description,SUM(salary)
FROMemployee
GROUPBYROLLUP(description,city);
CITYDESCRIPTIONSUM(SALARY)

NewYorkTester4322.78
VancouverTester16774.12
Tester21096.9
NewYorkManager7897.78
VancouverManager2344.78
Manager10242.56
TorontoProgrammer1234.56
Programmer1234.56
32574.02

PassingMultipleColumnstoROLLUP:groupstherowsintoblockswiththesamecolumnvalues
SELECTcity,description,SUM(salary)
FROMemployee
GROUPBYROLLUP(city,description);
CITYDESCRIPTIONSUM(SALARY)

TorontoProgrammer1234.56
Toronto1234.56
NewYorkTester4322.78
NewYorkManager7897.78
NewYork12220.56
VancouverTester16774.12
VancouverManager2344.78
Vancouver19118.9
32574.02

UsingAVGwithROLLUP
SELECTcity,description,AVG(salary)
FROMemployee
GROUPBYROLLUP(city,description);
CITYDESCRIPTIONAVG(SALARY)

TorontoProgrammer1234.56
Toronto1234.56

NewYorkTester4322.78
NewYorkManager7897.78
NewYork6110.28
VancouverTester4193.53
VancouverManager2344.78
Vancouver3823.78
4071.7525

Rollupfunctioningroupbyclause
SELECTcity,SUM(salary)
FROMemployee
GROUPBYROLLUP(city);
CITYSUM(SALARY)

NewYork12220.56
Toronto1234.56
Vancouver19118.9
32574.02

ROLLUPandRANK()togetthesalesrankingsbyproducttypeID
CREATETABLEall_sales(
yearINTEGER,
monthINTEGER,
prd_type_idINTEGER,
emp_idINTEGER,
amountNUMBER(8,2)
);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,1,1
,21,16034.84);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,2,1
,21,15644.65);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,3,2
,21,20167.83);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,4,2
,21,25056.45);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,5,2
,21,NULL);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,6,1
,21,15564.66);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,7,1
,21,15644.65);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,8,1
,21,16434.82);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,9,1
,21,19654.57);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,10,1
,21,21764.19);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,11,1
,21,13026.73);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2006,12,2
,21,10034.64);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,1,2
,22,16634.84);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,1,2
,21,26034.84);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,2,1
,21,12644.65);

insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,3,1
,21,NULL);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,4,1
,21,25026.45);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,5,1
,21,17212.66);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,6,1
,21,15564.26);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,7,2
,21,62654.82);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,8,2
,21,26434.82);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,9,2
,21,15644.65);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,10,2
,21,21264.19);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,11,1
,21,13026.73);
insertintoall_sales(YEAR,MONTH,PRD_TYPE_ID,EMP_ID,AMOUNT)values(2005,12,1
,21,10032.64);

select*fromall_sales;
YEARMONTHPRD_TYPE_IDEMP_IDAMOUNT

2006112116034.84
2006212115644.65
2006322120167.83
2006422125056.45
20065221
2006612115564.66
2006712115644.65
2006812116434.82
2006912119654.57
20061012121764.19
20061112113026.73
20061222110034.64
2005122216634.84
2005122126034.84
2005212112644.65
20053121
2005412125026.45
2005512117212.66
2005612115564.26
2005722162654.82
2005822126434.82
2005922115644.65
20051022121264.19
20051112113026.73
20051212110032.64

ROLLUPandRANK()togetthesalesrankingsbyproducttypeID
SELECT
prd_type_id,SUM(amount),
RANK()OVER(ORDERBYSUM(amount)DESC)ASrank
FROMall_sales
GROUPBYROLLUP(prd_type_id)

ORDERBYprd_type_id;
PRD_TYPE_IDSUM(AMOUNT)RANK

1227276.52
2223927.083
451203.581

CUBE
InadditiontothesubtotalsgeneratedbytheROLLUPextension,theCUBEextensionwillgenerate
subtotalsforallcombinationsofthedimensionsspecified.
If"n"isthenumberofcolumnslistedintheCUBE,therewillbe2nsubtotalcombinations.
SettingTestTable
DROPTABLEdimension_tab;
CREATETABLEdimension_tab(
fact_1_idNUMBERNOTNULL,
fact_2_idNUMBERNOTNULL,
fact_3_idNUMBERNOTNULL,
fact_4_idNUMBERNOTNULL,
sales_valueNUMBER(10,2)NOTNULL
);
INSERTINTOdimension_tab
SELECTTRUNC(DBMS_RANDOM.value(low=>1,high=>3))ASfact_1_id,
TRUNC(DBMS_RANDOM.value(low=>1,high=>6))ASfact_2_id,
TRUNC(DBMS_RANDOM.value(low=>1,high=>11))ASfact_3_id,
TRUNC(DBMS_RANDOM.value(low=>1,high=>11))ASfact_4_id,
ROUND(DBMS_RANDOM.value(low=>1,high=>100),2)ASsales_value
FROMdual
CONNECTBYlevel<=1000;
COMMIT;
SELECTfact_1_id,fact_2_id,
SUM(sales_value)ASsales_value
FROMdimension_tab
GROUPBYCUBE(fact_1_id,fact_2_id)
ORDERBYfact_1_id,fact_2_id;
FACT_1_IDFACT_2_IDSALES_VALUE

115806.42
124724.82
134358.52
145049.58
154929.04
124868.38
215181.96
225008.37
234856.44
244342.02
254619.73
224008.52
110988.38
29733.19
39214.96
49391.6

59548.77
48876.9

Asthenumberofdimensionsincrease,sodothecombinationsofsubtotalsthatneedtobecalculated
SELECTfact_1_id,fact_2_id,fact_3_id,
SUM(sales_value)ASsales_value
FROMdimension_tab
GROUPBYCUBE(fact_1_id,fact_2_id,fact_3_id)
ORDERBYfact_1_id,fact_2_id,fact_3_id;

Itispossibletodoapartialcubetoreducethenumberofsubtotalscalculated.
SELECTfact_1_id,fact_2_id,fact_3_id,
SUM(sales_value)ASsales_value
FROMdimension_tab
GROUPBYfact_1_id,CUBE(fact_2_id,fact_3_id)
ORDERBYfact_1_id,fact_2_id,fact_3_id;

GROUPINGFunctions
Itcanbequiteeasytovisuallyidentifysubtotalsgeneratedbyrollupsandcubes,buttodoit
programaticallyyoureallyneedsomethingmoreaccuratethanthepresenceofnullvaluesinthegrouping
columns.ThisiswheretheGROUPINGfunctioncomesin.Itacceptsasinglecolumnasaparameterand
returns"1"ifthecolumncontainsanullvaluegeneratedaspartofasubtotalbyaROLLUPorCUBE
operationor"0"foranyothervalue,includingstorednullvalues.
Thefollowingqueryisarepeatofapreviouscube,buttheGROUPINGfunctionhasbeenaddedforeach
ofthedimensionsinthecube.
SELECTfact_1_id,fact_2_id,
SUM(sales_value)ASsales_value,
GROUPING(fact_1_id)ASf1g,
GROUPING(fact_2_id)ASf2g
FROMdimension_tab
GROUPBYCUBE(fact_1_id,fact_2_id)
ORDERBYfact_1_id,fact_2_id;
FACT_1_IDFACT_2_IDSALES_VALUEF1GF2G

115806.4200
124724.8200
134358.5200
145049.5800
154929.0400
124868.3801
215181.9600
225008.3700
234856.4400
244342.0200
254619.7300
224008.5201
110988.3810
29733.1910
39214.9610
49391.610
59548.7710
48876.911

Fromthiswecansee:

F1G=0,F2G=0:RepresentsarowcontainingregularsubtotalwewouldexpectfromaGROUPBY
operation.
F1G=0,F2G=1:RepresentsarowcontainingasubtotalforadistinctvalueoftheFACT_1_IDcolumn,
asgeneratedbyROLLUPandCUBEoperations.
F1G=1,F2G=0:RepresentsarowcontainingasubtotalforadistinctvalueoftheFACT_2_IDcolumn,
whichwewouldonlyseeinaCUBEoperation.
F1G=1,F2G=1:Representsarowcontainingagrandtotalforthequery,asgeneratedbyROLLUPand
CUBEoperations.
Itwouldnowbeeasytowriteaprogramtoaccuratelyprocessthedata.
TheGROUPINGcolumnscanusedfororderingorfilteringresults.
SELECTfact_1_id,fact_2_id,
SUM(sales_value)ASsales_value,
GROUPING(fact_1_id)ASf1g,
GROUPING(fact_2_id)ASf2g
FROMdimension_tab
GROUPBYCUBE(fact_1_id,fact_2_id)
HAVINGGROUPING(fact_1_id)=1ORGROUPING(fact_2_id)=1
ORDERBYGROUPING(fact_1_id),GROUPING(fact_2_id);
FACT_1_IDFACT_2_IDSALES_VALUEF1GF2G

124868.3801
224008.5201
59548.7710
39214.9610
29733.1910
110988.3810
49391.610
48876.911

GROUPING_ID
TheGROUPING_IDfunctionprovidesanalternateandmorecompactwaytoidentifysubtotalrows.
Passingthedimensioncolumnsasarguments,itreturnsanumberindicatingtheGROUPBYlevel.
SELECTfact_1_id,fact_2_id,
SUM(sales_value)ASsales_value,
GROUPING_ID(fact_1_id,fact_2_id)ASgrouping_id
FROMdimension_tab
GROUPBYCUBE(fact_1_id,fact_2_id)
ORDERBYfact_1_id,fact_2_id;
FACT_1_IDFACT_2_IDSALES_VALUEGROUPING_ID

115806.420
124724.820
134358.520
145049.580
154929.040
124868.381
215181.960
225008.370
234856.440

244342.020
254619.730
224008.521
110988.382
29733.192
39214.962
49391.62
59548.772
48876.93

GROUP_ID
It'spossibletowritequeriesthatreturntheduplicatesubtotals,whichcanbealittleconfusing.The
GROUP_IDfunctionassignsthevalue"0"tothefirstset,andallsubsequentsetsgetassignedahigher
number.ThefollowingqueryforcesduplicatestoshowtheGROUP_IDfunctioninaction.
SELECTfact_1_id,fact_2_id,
SUM(sales_value)ASsales_value,
GROUPING_ID(fact_1_id,fact_2_id)ASgrouping_id,
GROUP_ID()ASgroup_id
FROMdimension_tab
GROUPBYGROUPINGSETS(fact_1_id,CUBE(fact_1_id,fact_2_id))
ORDERBYfact_1_id,fact_2_id;
FACT_1_IDFACT_2_IDSALES_VALUEGROUPING_IDGROUP_ID

115806.4200
124724.8200
134358.5200
145049.5800
154929.0400
124868.3810
124868.3811
215181.9600
225008.3700
234856.4400
244342.0200
254619.7300
224008.5211
224008.5210
110988.3820
29733.1920
39214.9620
49391.620
59548.7720
48876.930

Ifnecessary,youcouldthenfiltertheresultsusingthegroup.
SELECTfact_1_id,fact_2_id,
SUM(sales_value)ASsales_value,
GROUPING_ID(fact_1_id,fact_2_id)ASgrouping_id,
GROUP_ID()ASgroup_id
FROMdimension_tab
GROUPBYGROUPINGSETS(fact_1_id,CUBE(fact_1_id,fact_2_id))
HAVINGGROUP_ID()=0
ORDERBYfact_1_id,fact_2_id;

FACT_1_IDFACT_2_IDSALES_VALUEGROUPING_IDGROUP_ID

115806.4200
124724.8200
134358.5200
145049.5800
154929.0400
124868.3810
215181.9600
225008.3700
234856.4400
244342.0200
254619.7300
224008.5210
110988.3820
29733.1920
39214.9620
49391.620
59548.7720
48876.930

GROUPINGSETS
Calculatingallpossiblesubtotalsinacube,especiallythosewithmanydimensions,canbequitean
intensiveprocess.Ifyoudon'tneedallthesubtotals,thiscanrepresentaconsiderableamountofwasted
effort.Thefollowingcubewiththreedimensionsgives8levelsofsubtotals(GROUPING_ID:07),
shownhere.
SELECTfact_1_id,fact_2_id,fact_3_id,
SUM(sales_value)ASsales_value,
GROUPING_ID(fact_1_id,fact_2_id,fact_3_id)ASgrouping_id
FROMdimension_tab
GROUPBYCUBE(fact_1_id,fact_2_id,fact_3_id)
ORDERBYfact_1_id,fact_2_id,fact_3_id;

IfweonlyneedafewoftheselevelsofsubtotalingwecanusetheGROUPINGSETSexpressionand
specifyexactlywhichonesweneed,savingushavingtocalculatethewholecube.Inthefollowingquery
weareonlyinterestedinsubtotalsforthe"FACT_1_ID,FACT_2_ID"and"FACT_1_ID,FACT_3_ID"
groups.
SELECTfact_1_id,fact_2_id,fact_3_id,
SUM(sales_value)ASsales_value,
GROUPING_ID(fact_1_id,fact_2_id,fact_3_id)ASgrouping_id
FROMdimension_tab
GROUPBYGROUPINGSETS((fact_1_id,fact_2_id),(fact_1_id,fact_3_id))
ORDERBYfact_1_id,fact_2_id,fact_3_id;

FACT_1_IDFACT_2_IDFACT_3_IDSALES_VALUEGROUPING_ID

115806.421
124724.821
134358.521
145049.581
154929.041
112328.632

122562.872
132576.242
142489.732
152645.772
162795.962
172763.932
182448.432
192237.712
1102019.112
215181.961
225008.371
234856.441
244342.021
254619.731
212091.332
222299.232
232381.082
242884.192
252704.92
262364.082
272261.542
282582.82
292399.912
2102039.462

Noticehowwehavegonefromreturning198rowswith8subtotallevelsinthecube,tojust30rowswith
2subtotallevels
MoreExampleswithEMPTable
@connectscott/tiger
Analyticsrunningtotal
setlinesize100
setpagesize80
select*fromemporderbyDEPTNO;
EMPNOENAMEJOBMGRHIREDATESALCOMMDEPTNO

7782CLARKMANAGER783909/JUN/8100:00:00245010
7839KINGPRESIDENT17/NOV/8100:00:00500010
7934MILLERCLERK778223/JAN/8200:00:00130010
7566JONESMANAGER783902/APR/8100:00:00297520
7902FORDANALYST756603/DEC/8100:00:00300020
7876ADAMSCLERK778823/MAY/8700:00:00110020
7369SMITHCLERK790217/DEC/8000:00:0080020
7788SCOTTANALYST756619/APR/8700:00:00300020
7521WARDSALESMAN769822/FEB/8100:00:00125050030
7844TURNERSALESMAN769808/SEP/8100:00:001500030
7499ALLENSALESMAN769820/FEB/8100:00:00160030030
7900JAMESCLERK769803/DEC/8100:00:0095030
7698BLAKEMANAGER783901/MAY/8100:00:00285030
7654MARTINSALESMAN769828/SEP/8100:00:001250140030

GettingaSUMofSALbyDEPTNO
setechoon
breakondeptnoskip1

Selectdeptno,ename,sal,
sum(sal)over(partitionbydeptnoorderbysal)running_total1,
sum(sal)over(partitionbydeptnoorderbysal,rowid)running_total2
fromemporderbydeptno,sal;
DEPTNOENAMESALRUNNING_TOTAL1RUNNING_TOTAL2

10MILLER130013001300
CLARK245037503750
KING500087508750
20SMITH800800800
ADAMS110019001900
JONES297548754875
SCOTT3000108757875
FORD30001087510875
30JAMES950950950
WARD125034502200
MARTIN125034503450
TURNER150049504950
ALLEN160065506550
BLAKE285094009400

AnalyticsPercentageswithinagroup
breakondeptnoskip1
selectdeptno,ename,sal,
to_char(round(ratio_to_report(sal)over(partitionbydeptno)*100,2),'990.00'
)||'%'rtr
fromemp;
DEPTNOENAMESALRTR

10CLARK245028.00%
KING500057.14%
MILLER130014.86%
20JONES297527.36%
FORD300027.59%
ADAMS110010.11%
SMITH8007.36%
SCOTT300027.59%
30WARD125013.30%
TURNER150015.96%
ALLEN160017.02%
JAMES95010.11%
BLAKE285030.32%
MARTIN125013.30%

AnalyticsTopNqueries
setechoon
breakondeptnoskip1
selectdeptno,ename,sal,rn
from(Selectdeptno,ename,sal,row_number()over(partitionbydeptnoorderbysaldesc)
rn
fromemp)

wherern<=3;
DEPTNOENAMESALRN

10KING50001
CLARK24502
MILLER13003
20SCOTT30001
FORD30002
JONES29753
30BLAKE28501
ALLEN16002
TURNER15003

selectdeptno,ename,sal,rank
from(Selectdeptno,ename,sal,rank()over(partitionbydeptnoorderbysaldesc)rank
fromemp)
whererank<=3;
DEPTNOENAMESALRANK

10KING50001
CLARK24502
MILLER13003
20SCOTT30001
FORD30001
JONES29753
30BLAKE28501
ALLEN16002
TURNER15003

selectdeptno,ename,sal,dr
from(Selectdeptno,ename,sal,dense_rank()over(partitionbydeptnoorderbysaldesc)
dr
fromemp)
wheredr<=3;
DEPTNOENAMESALDR

10KING50001
CLARK24502
MILLER13003
20SCOTT30001
FORD30001
JONES29752
ADAMS11003
30BLAKE28501
ALLEN16002
TURNER15003

AnalyticsMovingAverages

columnlast_5formata30
setechoon
Selectename,sal,
round(avg(sal)over(orderbysalrows5preceding))avg_sal,
rtrim(lag(sal)over(orderbysal)||','||
lag(sal,2)over(orderbysal)||','||
lag(sal,3)over(orderbysal)||','||
lag(sal,4)over(orderbysal)||','||
lag(sal,5)over(orderbysal),',')last_5
fromemp
orderbysal;
ENAMESALAVG_SALLAST_5

SMITH800800
JAMES950875800
ADAMS1100950950,800
WARD125010251100,950,800
MARTIN125010701250,1100,950,800
MILLER130011081250,1250,1100,950,800
TURNER150012251300,1250,1250,1100,950
ALLEN160013331500,1300,1250,1250,1100
CLARK245015581600,1500,1300,1250,1250
BLAKE285018252450,1600,1500,1300,1250
JONES297521132850,2450,1600,1500,1300
SCOTT300023962975,2850,2450,1600,1500
FORD300026463000,2975,2850,2450,1600
KING500032133000,3000,2975,2850,2450

selectround((3000+3000+2975+2850+2450+5000)/6)fromdual
ROUND((3000+3000+2975+2850+2450+5000)/6)

3213

AnalyticsRankingQueries
setechoon
breakondeptnoskip1
Selectdeptno,ename,sal,
rank()over(partitionbydeptnoorderbysaldesc)r,
dense_rank()over(partitionbydeptnoorderbysaldesc)dr,
row_number()over(partitionbydeptnoorderbysaldesc)rn
fromemp
orderbydeptno,saldesc;
DEPTNOENAMESALRDRRN

10KING5000111
CLARK2450222
MILLER1300333
20SCOTT3000111
FORD3000112
JONES2975323
ADAMS1100434
SMITH800545
30BLAKE2850111
ALLEN1600222

TURNER1500333
MARTIN1250444
WARD1250445
JAMES950656

Das könnte Ihnen auch gefallen