oracle analytic sql ncoug 2008 by: ron warshawsky cto dba infopower, inc
TRANSCRIPT
Oracle Analytic SQL
NCOUG 2008
By: Ron Warshawsky CTO DBA InfoPower, Inc.
Oracle Analytic SQL
Note: “standard” name is “Window” functions
When? – Starting 8i
Why? – Simple Solution of Complex Problems
Why Exactly? – advanced ranking, aggregation, row comparison, statistics, “what if” scenarios
Order of Evaluation in SQL: Prior to “ORDER BY” clause
Oracle Analytic SQL
Syntax:
Analytic-Function(<Argument>,<Argument>,...)OVER ( <Query-Partition-Clause> <Order-By-Clause> <Windowing-Clause>)
PARTITION BY – aggregates result set into groups
ORDER BY – orders data within a partition
WINDOWING – rows or ranges (logical offset)
Oracle Analytic SQL
More Windowing:
<ROWS|RANGE> BETWEEN ... AND UNBOUNDED PRECEDING – start of partition UNBOUNDED FOLLOWING – end of partition CURRENT ROW value_expr < PRECEDING| FOLLOWING>
Examples:
ROWS BETWEEN 1 PRECEDING and 1 FOLLOWING
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
RANGE BETWEEN INTERVAL '7' day PRECEDING AND CURRENT ROW
Oracle Analytic SQL
Major Functions:
STANDARD AGGREGATE FUNCTIONSROW_NUMBER()LAG()LEAD()RANK()DENSE_RANK()PERCENT_RANK()NTILE()FIRST_VALUE()LAST_VALUE()FIRST()LAST()STATISTICAL FUNCTIONS
Oracle Analytic SQL
Practical Examples
Oracle Analytic SQL
Selecting the Top n Records
select sql_id, BUFFER_GETS_DELTAfrom ( select sql_id, BUFFER_GETS_DELTA, dense_rank() over (order by BUFFER_GETS_DELTA desc) dr from DBA_HIST_SQLSTAT) x where dr <= 5;
Oracle Analytic SQL
Calculate 3 period Moving Average
select snap_id ,sql_id ,BUFFER_GETS_DELTA ,avg(BUFFER_GETS_DELTA) over (order by snap_id rows between 1 preceding and 1 following ) MA_3snap_BGfrom DBA_HIST_SQLSTAT where sql_id = '0h6b2sajwb74n';
Oracle Analytic SQLCalculate 3 Day Moving Average
select BEGIN_INTERVAL_TIME ,sql_id ,BUFFER_GETS_DELTA ,avg(BUFFER_GETS_DELTA) over ( order by BEGIN_INTERVAL_TIME RANGE between interval '1' day preceding and interval '1' day following ) MA_3day_BGfrom DBA_HIST_SQLSTAT a ,dba_hist_snapshot bwhere a.INSTANCE_NUMBER = b.INSTANCE_NUMBER and a.SNAP_ID = b.SNAP_ID and sql_id = '0h6b2sajwb74n';
Oracle Analytic SQL
Sort Set by Most Frequently Occurring Items
select sql_id, CNT, dense_rank() over (order by cnt desc) as rnk from ( select sql_id,count(*) as cnt from DBA_HIST_SQLSTATgroup by sql_id) x
Oracle Analytic SQL
Identify Percentage of Total
select distinct sql_id, (sql_bg/total)*100 as pctfrom (select sql_id, sum(BUFFER_GETS_DELTA) over () total, sum(BUFFER_GETS_DELTA) over (partition by sql_id) sql_bgfrom DBA_HIST_SQLSTAT) xorder by 2;
Oracle Analytic SQL
Reduce Skewing (ignore highest and lowest value within a set)
select sql_id, avg(BUFFER_GETS_DELTA ) avg_bgfrom (select sql_id, BUFFER_GETS_DELTA, min(BUFFER_GETS_DELTA) over (partition by sql_id) min_bg, max(BUFFER_GETS_DELTA) over (partition by sql_id) max_bgfrom DBA_HIST_SQLSTAT) xwhere BUFFER_GETS_DELTA not in (min_bg, max_bg)group by sql_id;
Oracle Analytic SQL
Convert Rows into Columns
select max(case when object_type='TABLE‘ then object_name else null end) as TAB_NAME,max(case when object_type='INDEX‘ then object_name else null end) as IDX_NAMEfrom (select object_type ,object_name ,row_number() over (partition by object_type order by object_name) rnfrom dba_objectswhere object_type in ('TABLE', 'INDEX' )) xgroup by rnorder by 1;
Oracle Analytic SQL
Create fix size “buckets” of data
select
segment_name
ceil(row_number() over (order by segment_name)/50) grp,
from DBA_SEGMENTS
;
Oracle Analytic SQL
Create pre-defined number of data “buckets”
select
ntile(10) over (order by segment_name) grp,
segment_name
from DBA_SEGMENTS
;
Oracle Analytic SQL
Mix Aggregates from multiple groups
select sql_id, module, sum(BUFFER_GETS_DELTA ) over(partition by module) module_cnt, PARSING_SCHEMA_NAME, sum(BUFFER_GETS_DELTA ) over(partition by PARSING_SCHEMA_NAME) PARSING_SCHEMA_NAME_cnt, sum(BUFFER_GETS_DELTA ) over() totalfrom DBA_HIST_SQLSTAT;
Oracle Analytic SQL
Aggregating across moving historical ranges
select distinct x.*from (select trunc(BEGIN_INTERVAL_TIME ) SNAP_Date ,sum(BUFFER_GETS_DELTA) over (partition by trunc(BEGIN_INTERVAL_TIME ) ) snap_bg ,sum(BUFFER_GETS_DELTA ) over(order by trunc(BEGIN_INTERVAL_TIME ) range between 14 preceding and current row) prior_2week_bgfrom DBA_HIST_SQLSTAT a ,dba_hist_snapshot bwhere a.INSTANCE_NUMBER = b.INSTANCE_NUMBER and a.SNAP_ID = b.SNAP_ID) x;;
Oracle Analytic SQL
Identify Consecutive Ranges of Time
select a.sql_id, b.BEGIN_INTERVAL_TIME snap_time, lead(b.BEGIN_INTERVAL_TIME) over (order by a.snap_id) next_snap_timefrom DBA_HIST_SQLSTAT a ,dba_hist_snapshot bwhere a.INSTANCE_NUMBER = b.INSTANCE_NUMBER and a.SNAP_ID = b.SNAP_ID and sql_id = '83taa7kaw59c1'
Oracle Analytic SQL
Access Future and Historical rows
select snap_id ,BUFFER_GETS_DELTA ,nvl(lead(BUFFER_GETS_DELTA) over (order by snap_id, BUFFER_GETS_DELTA ) , null ) forward ,nvl(lag (BUFFER_GETS_DELTA) over (order by snap_id, BUFFER_GETS_DELTA ) , null ) backwardfrom ( select snap_id ,sum(BUFFER_GETS_DELTA ) BUFFER_GETS_DELTAfrom DBA_HIST_SQLSTAT group by snap_id) xorder by 1;
Oracle Analytic SQL
Select every N-th row
select SNAP_IDfrom (select snap_id ,row_number( ) over (order by snap_id) rnfrom dba_hist_snapshot ) xwhere mod(rn,5) = 1;
Oracle Analytic SQL
Remove Duplicate without use of Distinct
select sql_idfrom (select sql_id, row_number( ) over (partition by sql_id order by sql_id) rnfrom DBA_HIST_SQLSTAT ) xwhere rn = 1;
Oracle Analytic SQL
Q&A