Really UsingAnalytic Functions        Kim Berg Hansen    T. Hansen Gruppen A/S
Who is this Kim?                    • a Danish SQL and PL/SQL Developer:                           http://dspsd.blogspot.c...
What’s up?    •   Why analytics?    •   Case 1: Top selling items    •   Case 2: Picking by FIFO    •   Case 3: Efficient ...
Why analytics?    • Normal SQL functions operate on one row    • Aggregates can do more rows but loose detail    • When yo...
Top Selling Items    Case 15       2012-12-05   #ukoug2012   Really Using Analytic Functions
Top selling items• Classic task for a programmer:• Show top three by product group• Also show how big percentage they  sol...
Tables    create table items(       item varchar2(10) primary key,                                                        ...
Data - items    insert   into   items   values   (101010,AUTO,Brake disc);    insert   into   items   values   (102020,AUT...
Data – sales AUTO    insert   into   sales   values   (101010,date    2011-04-01,10);    insert   into   sales   values   ...
Data – sales MOBILE     insert   into   sales   values   (201010,date    2011-04-01, 5);     insert   into   sales   value...
Base select select   i.grp      ,   i.item                                                                            Join...
Base select GRP          ITEM         NAME                   QTY ----------   ----------   -------------------- -----     ...
Which TOP? select        g.grp, g.item, g.name, g.qty      ,        dense_rank() over (partition by g.grp order by g.qty d...
Which TOP? GRP          ITEM         NAME                   QTY DRNK    RNK RNUM ----------   ----------   ---------------...
Without inline view select   i.grp      ,   i.item                                              Analytics calculated last,...
Without inline view GRP          ITEM         NAME                   QTY DRNK    RNK RNUM ----------   ----------   ------...
TOP 3 – rank() select g.grp, g.item, g.name, g.qty, g.rnk   from (                                                        ...
TOP 3 – rank() GRP          ITEM         NAME                   QTY   RNK ----------   ----------   -------------------- -...
TOP 3 – dense_rank() select g.grp, g.item, g.name, g.qty, g.rnk   from (     select i.grp           , i.item           , m...
TOP 3 – dense_rank() GRP          ITEM         NAME                   QTY   RNK ----------   ----------   ----------------...
TOP 3 – row_number() select g.grp, g.item, g.name, g.qty, g.rnk   from (     select i.grp           , i.item           , m...
TOP 3 – row_number() GRP          ITEM         NAME                   QTY   RNK ----------   ----------   ----------------...
Percent of total select g.grp, g.item, g.name, g.qty, g.rnk      , round(g.g_pct,1) g_pct                                 ...
Percent of total GRP          ITEM         NAME                   QTY   RNK G_PCT T_PCT ----------   ----------   --------...
Top selling items     • What kind of top three do you wish?        – DENSE_RANK()        – RANK()        – ROW_NUMBER()   ...
Picking by FIFO     Case 226       2012-12-05   #ukoug2012   Really Using Analytic Functions
Picking by FIFO     • Items stored in different locations in warehouse     • Pick an order by First-In First-Out principle...
Tables create table inventory (    item varchar2(10),                                                                     ...
Data     insert   into   inventory   values(A1,   1-A-20,   18,   DATE   2004-11-01);     insert   into   inventory   valu...
What to pick Picking application sets bind variable for which order to pick (Could be sales order, batch order, shop refil...
What can we pick select o.item      , o.qty ord_qty                                                                       ...
What can we pick ITEM       ORD_QTY LOC        PURCH      LOC_QTY ---------- ------- ---------- ---------- -------        ...
Accumulate select    o.item      ,    o.qty ord_qty                                                                       ...
Accumulate ITEM       ORD_QTY LOC        PURCH      LOC_QTY SUM_QTY ---------- ------- ---------- ---------- ------- -----...
Filter accumulated select s.* from (                                                                      So let’s try to ...
Filter accumulated ITEM       ORD_QTY LOC        PURCH      LOC_QTY SUM_QTY ---------- ------- ---------- ---------- -----...
Accumulate previous select    o.item      ,    o.qty ord_qty                                                              ...
Accumulate previous ITEM       ORD_QTY LOC        PURCH      LOC_QTY SUM_PRV_QTY ---------- ------- ---------- ---------- ...
Filter previous select s.*      , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty                 Now we can filter f...
Filter previous ITEM       ORD_QTY LOC        PURCH      LOC_QTY SUM_PRV_QTY PICK_QTY ---------- ------- ---------- ------...
Picking list FIFO select s.loc      , s.item                                                               Now order by   ...
Picking list FIFO LOC          ITEM       PICK_QTY ----------   ---------- --------                                       ...
Picking small qty select s.loc      , s.item                                                               Change pick pol...
Picking small qty LOC          ITEM       PICK_QTY ----------   ---------- --------                                       ...
Picking few picks select s.loc      , s.item                                                               Or policy of pi...
Picking few picks LOC          ITEM       PICK_QTY ----------   ---------- --------                                       ...
Picking short route select s.loc      , s.item                                                               Policy of not...
Picking short route LOC          ITEM       PICK_QTY ----------   ---------- --------                                     ...
Picking by FIFO     • SUM() by item     • Ordered by purchase date     • Rolling sum to find how much was picked by ”previ...
Efficient picking route     Case 350       2012-12-05    #ukoug2012   Really Using Analytic Functions
Picking small qty select s.loc      , s.item                                                               Same data as FI...
Picking small qty LOC          ITEM       PICK_QTY ----------   ---------- --------                                       ...
Picking route     • Is this a smart route to drive?53      2012-12-05   #ukoug2012   Really Using Analytic Functions
Better picking route     • We need to change direction every other aisle54      2012-12-05   #ukoug2012   Really Using Ana...
Decipher loc select       to_number(substr(s.loc,1,1)) warehouse      ,       substr(s.loc,3,1) aisle                     ...
Decipher loc WAREHOUSE   AISLE POSITION LOC        ITEM       PICK_QTY ---------   ----- -------- ---------- ---------- --...
Rank aisles select to_number(substr(s.loc,1,1)) warehouse      , substr(s.loc,3,1) aisle                                  ...
Rank aisles WAREHOUSE   AISLE AISLE_NO POSITION LOC           ITEM       PICK_QTY ---------   ----- -------- -------- ----...
Odd up, even down select      s2.warehouse, s2.aisle, s2.aisle_no, s2.position, s2.loc, s2.item, s2.pick_qty              ...
Odd up, even down WAREHOUSE   AISLE AISLE_NO POSITION LOC           ITEM       PICK_QTY ---------   ----- -------- -------...
Single door     • Direction has to ”restart” per warehouse61     2012-12-05   #ukoug2012   Really Using Analytic Functions
Partition warehouse select s2.warehouse, s2.aisle, s2.aisle_no, s2.position, s2.loc, s2.item, s2.pick_qty from (      sele...
Partition warehouse WAREHOUSE   AISLE AISLE_NO POSITION LOC           ITEM       PICK_QTY ---------   ----- -------- -----...
Efficient picking route     • DENSE_RANK() to number the aisles in order visited     • Order the output        – ”Up” on o...
Picking efficiency     Case 465       2012-12-05   #ukoug2012   Really Using Analytic Functions
Picking efficiency                                            • How fast can operators                                    ...
Table create table missions (    missionid      number   primary key,                                                     ...
Mission datainsert into missions   values   (   35986751,   10063485,   STORE,    timestamp    2012-04-12    06:38:07,    ...
Arrivals select    a.arrivepos pos      ,    a.arrivetime time                                                            ...
Arrivals POS    TIME      LOADUNIT MISSIONID ----   -------- --------- --------- PLF4   08:00:03 10063485 35986751 PLF4   ...
Departures select    d.departpos pos      ,    d.departtime time                                                          ...
Departures POS    TIME      LOADUNIT MISSIONID ----   -------- --------- --------- PLF4   08:00:00 10067235 35988299 PLF4 ...
Combined events select pos, time, ad, loadunit, missionid   from (    select a.arrivepos pos, a.arrivetime time,     A ad,...
Combined events POS    TIME       AD LOADUNIT MISSIONID ----   --------   -- --------- ---------                          ...
Lead the next event with s1 as (     select a.arrivepos pos, a.arrivetime time,       from missions a                     ...
Lead the next event POS    TIME       NEXTTIME   AD LOADUNIT ----   --------   --------   -- ---------                    ...
Lead on with s1 as (     select a.arrivepos pos, a.arrivetime time,       from missions a      where a.arrivepos in (PLF4,...
Lead on POS    TIME       NEXTTIME   NEXT2TIM   AD LOADUNIT ----   --------   --------   --------   -- ---------          ...
Filter double lead with s1 as (    select a.arrivepos pos, a.arrivetime time,   A ad, a.loadunit, a.missionid      from mi...
Filter double lead POS    ARRIVE     DEPART     NEXTARRI LOADUNIT ----   --------   --------   -------- ---------         ...
Pick and wait with s1 as ( ... ) select     pos, arrive, depart, nextarrive                                               ...
Pick and wait POS    ARRIVE     DEPART     NEXTARRI PICKSECONDS WAITSECONDS ----   --------   --------   -------- --------...
Hourly stats with s1 as ( ... ) select      ,                                 pos                                 trunc(ar...
Hourly stats                             sec                sec                sec        cycle                           ...
Picking efficiency     • Log over tote missions arriving and departing the       picking stations     • LEAD() on mission ...
Forecasting sales     Case 586       2012-12-05   #ukoug2012   Really Using Analytic Functions
Forecasting sales• Forecast the sales  of next year• But follow the  trend of the item87    2012-12-05   #ukoug2012   Real...
Table create table sales (    item     varchar2(10),                                                                      ...
Data     insert   into sales values (Snowchain, date 2008-01-01,                      79);     insert   into sales values ...
Slope select    sales.item         Graph slope: y-axis is qty      ,    sales.mth      ,    sales.qty                     ...
Slope ITEM         MTH          QTY    SLOPE ----------   ---------- ----- --------                                       ...
Transpose using slope select item, mth, qty      , qty + 12 * slope qty_next_year                                         ...
Transpose using slope ITEM         MTH          QTY QTY_NEXT_YEAR ----------   ---------- ----- ------------- Snowchain   ...
Forecast select    item      ,    add_months(mth, 12) mth                                                                 ...
Forecast ITEM         MTH         FORECAST ----------   ---------- --------- Snowchain    2011-01-01       188            ...
Actual + forecast select item, mth, qty, type   from (    select sales.item, sales.mth, sales.qty, Actual type            ...
Actual + forecast ITEM         MTH          QTY TYPE ----------   ---------- ----- ---------- Snowchain    2008-01-01    7...
Actual + forecastData from previous  slide is the graph• ”Actual” is  normal lines• ”Forecast” is  stapled lines98    2012...
Forecasting sales     • REGR_SLOPE() to calculate trend     • RANGE window for sliding trend calculation over       three ...
Forecast zero stock      Case 6100       2012-12-05   #ukoug2012   Really Using Analytic Functions
Forecast zero stock                                             • Fireworks sell like crazy                               ...
Tables create table fw_store (   shopid      varchar2(10) primary key,                                                    ...
Tables create table fw_daybudget (   shopid      varchar2(10) references fw_store (shopid),                               ...
Data - store      insert into fw_store values (AALBORG , 4);      insert into fw_store values (GLOSTRUP , 4);      insert ...
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Really using Oracle analytic SQL functions
Upcoming SlideShare
Loading in...5
×

Really using Oracle analytic SQL functions

2,255

Published on

Presentation on Oracle analytic SQL functions as I presented it on UKOUG 2012 conference in Birmingham

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,255
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
98
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Really using Oracle analytic SQL functions

  1. 1. Really UsingAnalytic Functions Kim Berg Hansen T. Hansen Gruppen A/S
  2. 2. Who is this Kim? • a Danish SQL and PL/SQL Developer: http://dspsd.blogspot.com • Professional geek since 1996 • Oracle programmer since 2000 • Single SQL Statement mantra (©Tom Kyte) • Danish Beer Enthusiast (http://ale.dk) • Likes to cook • Reads sci-fi2 2012-12-05 #ukoug2012 Really Using Analytic Functions
  3. 3. What’s up? • Why analytics? • Case 1: Top selling items • Case 2: Picking by FIFO • Case 3: Efficient picking route • Case 4: Picking efficiency • Case 5: Forecasting sales • Case 6: Forecast zero firework stock • Case 7: Multi-order FIFO picking (time permitting) • Any questions?3 2012-12-05 #ukoug2012 Really Using Analytic Functions
  4. 4. Why analytics? • Normal SQL functions operate on one row • Aggregates can do more rows but loose detail • When you need details together with subtotals, ranks, ratios, comparisons, you could do:  Client operations (tool or code with variables/arrays)  Scalar subqueries (multiple access of same data)  Analytic functions (often much more efficient ) • Analytics allow you to operate across the entire resultset, not just a single row4 2012-12-05 #ukoug2012 Really Using Analytic Functions
  5. 5. Top Selling Items Case 15 2012-12-05 #ukoug2012 Really Using Analytic Functions
  6. 6. Top selling items• Classic task for a programmer:• Show top three by product group• Also show how big percentage they sold of the total – Both of the total by product group – And of the grand total6 2012-12-05 #ukoug2012 Really Using Analytic Functions
  7. 7. Tables create table items( item varchar2(10) primary key, Items with groups grp varchar2(10), name varchar2(20) ) / create table sales ( Sales per month item varchar2(10) references items (item), mth date, qty number ) /7 2012-12-05 #ukoug2012 Really Using Analytic Functions
  8. 8. Data - items insert into items values (101010,AUTO,Brake disc); insert into items values (102020,AUTO,Snow chain); 5 autoparts insert into items values (103030,AUTO,Sparc plug); insert into items values (104040,AUTO,Oil filter); insert into items values (105050,AUTO,Light bulb); insert into items values (201010,MOBILE,Handsfree); insert into items values (202020,MOBILE,Charger); 5 mobile insert into items values (203030,MOBILE,iGloves); insert into items values (204040,MOBILE,Headset); accessories insert into items values (205050,MOBILE,Cover);8 2012-12-05 #ukoug2012 Really Using Analytic Functions
  9. 9. Data – sales AUTO insert into sales values (101010,date 2011-04-01,10); insert into sales values (101010,date 2011-05-01,11); Sales for various insert into sales values (101010,date 2011-06-01,12); months of 2011 for insert into sales values (102020,date 2011-03-01, 7); the autoparts insert into sales values (102020,date 2011-07-01, 8); insert into sales values (103030,date 2011-01-01, 6); insert into sales values (103030,date 2011-02-01, 9); insert into sales values (103030,date 2011-11-01, 4); insert into sales values (103030,date 2011-12-01,14); insert into sales values (104040,date 2011-08-01,22); insert into sales values (105050,date 2011-09-01,13); insert into sales values (105050,date 2011-10-01,15);9 2012-12-05 #ukoug2012 Really Using Analytic Functions
  10. 10. Data – sales MOBILE insert into sales values (201010,date 2011-04-01, 5); insert into sales values (201010,date 2011-05-01, 6); Sales for various insert into sales values (201010,date 2011-06-01, 7); months of 2011 for insert into sales values (202020,date 2011-03-01,21); the mobile insert into sales values (202020,date 2011-07-01,23); insert into sales values (203030,date 2011-01-01, 7); accessories insert into sales values (203030,date 2011-02-01, 7); insert into sales values (203030,date 2011-11-01, 6); insert into sales values (203030,date 2011-12-01, 8); insert into sales values (204040,date 2011-08-01,35); insert into sales values (205050,date 2011-09-01,13); insert into sales values (205050,date 2011-10-01,15);10 2012-12-05 #ukoug2012 Really Using Analytic Functions
  11. 11. Base select select i.grp , i.item Join items and sales , max(i.name) name , sum(s.qty) qty from items i Sales for 2011 join sales s on s.item = i.item where s.mth between date 2011-01-01 and date 2011-12-01 Group by to get group by i.grp, i.item order by i.grp, sum(s.qty) desc, i.item total sales for 2011 per item11 2012-12-05 #ukoug2012 Really Using Analytic Functions
  12. 12. Base select GRP ITEM NAME QTY ---------- ---------- -------------------- ----- Couple of items in AUTO 101010 Brake disc 33 each group have AUTO 103030 Sparc plug 33 identical sales AUTO 105050 Light bulb 28 AUTO 104040 Oil filter 22 AUTO 102020 Snow chain 15 MOBILE 202020 Charger 44 MOBILE 204040 Headset 35 MOBILE 203030 iGloves 28 MOBILE 205050 Cover 28 MOBILE 201010 Handsfree 1812 2012-12-05 #ukoug2012 Really Using Analytic Functions
  13. 13. Which TOP? select g.grp, g.item, g.name, g.qty , dense_rank() over (partition by g.grp order by g.qty desc) drnk , rank() over (partition by g.grp order by g.qty desc) rnk , row_number() over (partition by g.grp order by g.qty desc, g.item) rnum from ( select i.grp , i.item , max(i.name) name , from sum(s.qty) qty items i Base select as join on sales s s.item = i.item inline view where s.mth between date 2011-01-01 and date 2011-12-01 group by i.grp, i.item ) g order by g.grp, g.qty desc, g.item13 2012-12-05 #ukoug2012 Really Using Analytic Functions
  14. 14. Which TOP? GRP ITEM NAME QTY DRNK RNK RNUM ---------- ---------- -------------------- ----- ----- ----- ----- The three different AUTO 101010 Brake disc 33 1 1 1 functions handle AUTO 103030 Sparc plug 33 1 1 2 ties differently AUTO 105050 Light bulb 28 2 3 3 AUTO 104040 Oil filter 22 3 4 4 AUTO 102020 Snow chain 15 4 5 5 MOBILE 202020 Charger 44 1 1 1 MOBILE 204040 Headset 35 2 2 2 MOBILE 203030 iGloves 28 3 3 3 MOBILE 205050 Cover 28 3 3 4 MOBILE 201010 Handsfree 18 4 5 514 2012-12-05 #ukoug2012 Really Using Analytic Functions
  15. 15. Without inline view select i.grp , i.item Analytics calculated last, so can include , max(i.name) name group by expressions as well as aggregates , sum(s.qty) qty , dense_rank() over (partition by i.grp order by sum(s.qty) desc) drnk , rank() over (partition by i.grp order by sum(s.qty) desc) rnk , row_number() over (partition by i.grp order by sum(s.qty) desc, i.item) rnum from items i join sales s on s.item = i.item where s.mth between date 2011-01-01 and date 2011-12-01 group by i.grp, i.item order by i.grp, sum(s.qty) desc, i.item15 2012-12-05 #ukoug2012 Really Using Analytic Functions
  16. 16. Without inline view GRP ITEM NAME QTY DRNK RNK RNUM ---------- ---------- -------------------- ----- ----- ----- ----- Identical results AUTO 101010 Brake disc 33 1 1 1 AUTO 103030 Sparc plug 33 1 1 2 AUTO 105050 Light bulb 28 2 3 3 AUTO 104040 Oil filter 22 3 4 4 AUTO 102020 Snow chain 15 4 5 5 MOBILE 202020 Charger 44 1 1 1 MOBILE 204040 Headset 35 2 2 2 MOBILE 203030 iGloves 28 3 3 3 MOBILE 205050 Cover 28 3 3 4 MOBILE 201010 Handsfree 18 4 5 516 2012-12-05 #ukoug2012 Really Using Analytic Functions
  17. 17. TOP 3 – rank() select g.grp, g.item, g.name, g.qty, g.rnk from ( Analytic function select i.grp cannot be in , i.item , max(i.name) name where clause , sum(s.qty) qty , rank() over (partition by i.grp order by sum(s.qty) desc) rnk from items i So inline view join sales s on s.item = i.item and filter on the where s.mth between date 2011-01-01 and date 2011-12-01 alias group by i.grp, i.item ) g where g.rnk <= 3 order by g.grp, g.rnk, g.item17 2012-12-05 #ukoug2012 Really Using Analytic Functions
  18. 18. TOP 3 – rank() GRP ITEM NAME QTY RNK ---------- ---------- -------------------- ----- ----- rank() works like the AUTO 101010 Brake disc 33 1 olympics – two gold AUTO 103030 Sparc plug 33 1 medals mean no AUTO 105050 Light bulb 28 3 MOBILE 202020 Charger 44 1 silver medal MOBILE 204040 Headset 35 2 MOBILE 203030 iGloves 28 3 MOBILE 205050 Cover 28 318 2012-12-05 #ukoug2012 Really Using Analytic Functions
  19. 19. TOP 3 – dense_rank() select g.grp, g.item, g.name, g.qty, g.rnk from ( select i.grp , i.item , max(i.name) name , sum(s.qty) qty , dense_rank() over (partition by i.grp order by sum(s.qty) desc) rnk from items i join sales s on s.item = i.item where s.mth between date 2011-01-01 and date 2011-12-01 group by i.grp, i.item ) g where g.rnk <= 3 order by g.grp, g.rnk, g.item19 2012-12-05 #ukoug2012 Really Using Analytic Functions
  20. 20. TOP 3 – dense_rank() GRP ITEM NAME QTY RNK ---------- ---------- -------------------- ----- ----- dense_rank() also AUTO 101010 Brake disc 33 1 gives equal rank at AUTO 103030 Sparc plug 33 1 ties, but does not AUTO 105050 Light bulb 28 2 AUTO 104040 Oil filter 22 3 skip ranks MOBILE 202020 Charger 44 1 MOBILE 204040 Headset 35 2 MOBILE 203030 iGloves 28 3 MOBILE 205050 Cover 28 320 2012-12-05 #ukoug2012 Really Using Analytic Functions
  21. 21. TOP 3 – row_number() select g.grp, g.item, g.name, g.qty, g.rnk from ( select i.grp , i.item , max(i.name) name , sum(s.qty) qty , row_number() over (partition by i.grp order by sum(s.qty) desc, i.item) rnk from items i join sales s on s.item = i.item where s.mth between date 2011-01-01 and date 2011-12-01 group by i.grp, i.item ) g where g.rnk <= 3 order by g.grp, g.rnk, g.item21 2012-12-05 #ukoug2012 Really Using Analytic Functions
  22. 22. TOP 3 – row_number() GRP ITEM NAME QTY RNK ---------- ---------- -------------------- ----- ----- row_number() just AUTO 101010 Brake disc 33 1 numbers AUTO 103030 Sparc plug 33 2 consecutively AUTO 105050 Light bulb 28 3 MOBILE 202020 Charger 44 1 MOBILE 204040 Headset 35 2 MOBILE 203030 iGloves 28 3 If ties, then result is ”random”, so a good idea always to use ”unique” order by22 2012-12-05 #ukoug2012 Really Using Analytic Functions
  23. 23. Percent of total select g.grp, g.item, g.name, g.qty, g.rnk , round(g.g_pct,1) g_pct ratio_to_report() , round(g.t_pct,1) t_pct from ( returns number select i.grp , i.item between 0 and 1 , max(i.name) name , sum(s.qty) qty , rank() over (partition by i.grp order by sum(s.qty) desc) rnk , 100 * ratio_to_report(sum(s.qty)) over (partition by i.grp) g_pct , 100 * ratio_to_report(sum(s.qty)) over () t_pct Multiply with 100 to from items i join sales s get percent on s.item = i.item where s.mth between date 2011-01-01 and date 2011-12-01 group by i.grp, i.item ) g where g.rnk <= 3 order by g.grp, g.rnk, g.item23 2012-12-05 #ukoug2012 Really Using Analytic Functions
  24. 24. Percent of total GRP ITEM NAME QTY RNK G_PCT T_PCT ---------- ---------- -------------------- ----- ----- ------ ------ AUTO 101010 Brake disc 33 1 25.2 11.6 AUTO 103030 Sparc plug 33 1 25.2 11.6 AUTO 105050 Light bulb 28 3 21.4 9.9 MOBILE 202020 Charger 44 1 28.8 15.5 MOBILE 204040 Headset 35 2 22.9 12.3 MOBILE 203030 iGloves 28 3 18.3 9.9 MOBILE 205050 Cover 28 3 18.3 9.924 2012-12-05 #ukoug2012 Really Using Analytic Functions
  25. 25. Top selling items • What kind of top three do you wish? – DENSE_RANK() – RANK() – ROW_NUMBER() • PARTITION BY groups of items • RATIO_TO_REPORT for percentages25 2012-12-05 #ukoug2012 Really Using Analytic Functions
  26. 26. Picking by FIFO Case 226 2012-12-05 #ukoug2012 Really Using Analytic Functions
  27. 27. Picking by FIFO • Items stored in different locations in warehouse • Pick an order by First-In First-Out principle27 2012-12-05 #ukoug2012 Really Using Analytic Functions
  28. 28. Tables create table inventory ( item varchar2(10), Item, location, quan loc varchar2(10), tity and date of qty number, purchase purch date ) / create table orderline ( Order number, ordno number, item varchar2(10), item and quantity qty number ordered ) /28 2012-12-05 #ukoug2012 Really Using Analytic Functions
  29. 29. Data insert into inventory values(A1, 1-A-20, 18, DATE 2004-11-01); insert into inventory values(A1, 1-A-31, 12, DATE 2004-11-05); 2 items each 5 insert into inventory values(A1, 1-C-05, 18, DATE 2004-11-03); locations various insert into inventory values(A1, 2-A-02, 24, DATE 2004-11-02); insert into inventory values(A1, 2-D-07, 9, DATE 2004-11-04); purchase dates insert into inventory values(B1, 1-A-02, 18, DATE 2004-11-06); insert into inventory values(B1, 1-B-11, 4, DATE 2004-11-05); insert into inventory values(B1, 1-C-04, 12, DATE 2004-11-03); insert into inventory values(B1, 1-B-15, 2, DATE 2004-11-02); insert into inventory values(B1, 2-D-23, 1, DATE 2004-11-04); insert into orderline values (1,A1,24); One order with a insert into orderline values (1,B1,18); quantity of both items29 2012-12-05 #ukoug2012 Really Using Analytic Functions
  30. 30. What to pick Picking application sets bind variable for which order to pick (Could be sales order, batch order, shop refill order) variable pick_order number; begin :pick_order := 1; end; /30 2012-12-05 #ukoug2012 Really Using Analytic Functions
  31. 31. What can we pick select o.item , o.qty ord_qty Join orderline to , i.loc inventory to see all , i.purch that potentially can , i.qty loc_qty from orderline o be picked join inventory i on i.item = o.item where o.ordno = :pick_order order by o.item, i.purch, i.loc31 2012-12-05 #ukoug2012 Really Using Analytic Functions
  32. 32. What can we pick ITEM ORD_QTY LOC PURCH LOC_QTY ---------- ------- ---------- ---------- ------- Visually we can see A1 24 1-A-20 2004-11-01 18 we need 18 A1 from A1 24 2-A-02 2004-11-02 24 first location and 6 A1 24 1-C-05 2004-11-03 18 A1 24 2-D-07 2004-11-04 9 from second loc. A1 24 1-A-31 2004-11-05 12 B1 18 1-B-15 2004-11-02 2 B1 18 1-C-04 2004-11-03 12 Likewise we will B1 18 2-D-23 2004-11-04 1 empty first 3 locs of B1 18 1-B-11 2004-11-05 4 B1 18 1-A-02 2004-11-06 18 B1 and pick 3 from fourth location32 2012-12-05 #ukoug2012 Really Using Analytic Functions
  33. 33. Accumulate select o.item , o.qty ord_qty Let’s try to create a , i.loc rolling sum of the , i.purch , i.qty loc_qty qty for each item , sum(i.qty) over ( partition by i.item order by i.purch, i.loc rows between unbounded preceding and current row ) sum_qty from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order order by o.item, i.purch, i.loc33 2012-12-05 #ukoug2012 Really Using Analytic Functions
  34. 34. Accumulate ITEM ORD_QTY LOC PURCH LOC_QTY SUM_QTY ---------- ------- ---------- ---------- ------- ------- Yup, when our sum A1 24 1-A-20 2004-11-01 18 18 is greater than the A1 24 2-A-02 2004-11-02 24 42 ordered qty, it looks A1 24 1-C-05 2004-11-03 18 60 A1 24 2-D-07 2004-11-04 9 69 like we have enough A1 24 1-A-31 2004-11-05 12 81 B1 18 1-B-15 2004-11-02 2 2 B1 18 1-C-04 2004-11-03 12 14 B1 18 2-D-23 2004-11-04 1 15 B1 18 1-B-11 2004-11-05 4 19 B1 18 1-A-02 2004-11-06 18 3734 2012-12-05 #ukoug2012 Really Using Analytic Functions
  35. 35. Filter accumulated select s.* from ( So let’s try to filter select o.item, o.qty ord_qty , i.loc, i.purch, i.qty loc_qty on that , sum(i.qty) over ( partition by i.item order by i.purch, i.loc rows between unbounded preceding and current row ) sum_qty from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order ) s where s.sum_qty < s.ord_qty order by s.item, s.purch, s.loc35 2012-12-05 #ukoug2012 Really Using Analytic Functions
  36. 36. Filter accumulated ITEM ORD_QTY LOC PURCH LOC_QTY SUM_QTY ---------- ------- ---------- ---------- ------- ------- FAIL! A1 24 1-A-20 2004-11-01 18 18 B1 18 1-B-15 2004-11-02 2 2 B1 18 1-C-04 2004-11-03 12 14 Missing the last B1 18 2-D-23 2004-11-04 1 15 location for each item36 2012-12-05 #ukoug2012 Really Using Analytic Functions
  37. 37. Accumulate previous select o.item , o.qty ord_qty One small change to , i.loc our rolling sum: , i.purch , i.qty loc_qty , sum(i.qty) over ( partition by i.item Sum of rows up to order by i.purch, i.loc but not including rows between unbounded preceding and 1 preceding ) sum_prv_qty the current row from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order order by o.item, i.purch, i.loc37 2012-12-05 #ukoug2012 Really Using Analytic Functions
  38. 38. Accumulate previous ITEM ORD_QTY LOC PURCH LOC_QTY SUM_PRV_QTY ---------- ------- ---------- ---------- ------- ----------- As long as the sum A1 24 1-A-20 2004-11-01 18 of the previous rows A1 24 2-A-02 2004-11-02 24 18 are not enough, we A1 24 1-C-05 2004-11-03 18 42 A1 24 2-D-07 2004-11-04 9 60 continue A1 24 1-A-31 2004-11-05 12 69 B1 18 1-B-15 2004-11-02 2 B1 18 1-C-04 2004-11-03 12 2 When the previous B1 18 2-D-23 2004-11-04 1 14 rows are sufficient, B1 18 1-B-11 2004-11-05 4 15 B1 18 1-A-02 2004-11-06 18 19 we stop38 2012-12-05 #ukoug2012 Really Using Analytic Functions
  39. 39. Filter previous select s.* , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty Now we can filter from ( select o.item, o.qty ord_qty correctly , i.loc, i.purch, i.qty loc_qty , nvl(sum(i.qty) over ( partition by i.item order by i.purch, i.loc nvl() for first row rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from orderline o join inventory i on i.item = o.item least() to get qty to where o.ordno = :pick_order be picked at that ) s where s.sum_prv_qty < s.ord_qty location order by s.item, s.purch, s.loc39 2012-12-05 #ukoug2012 Really Using Analytic Functions
  40. 40. Filter previous ITEM ORD_QTY LOC PURCH LOC_QTY SUM_PRV_QTY PICK_QTY ---------- ------- ---------- ---------- ------- ----------- -------- A1 24 1-A-20 2004-11-01 18 0 18 A1 24 2-A-02 2004-11-02 24 18 6 B1 18 1-B-15 2004-11-02 2 0 2 B1 18 1-C-04 2004-11-03 12 2 12 B1 18 2-D-23 2004-11-04 1 14 1 B1 18 1-B-11 2004-11-05 4 15 340 2012-12-05 #ukoug2012 Really Using Analytic Functions
  41. 41. Picking list FIFO select s.loc , s.item Now order by , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( location to make a select o.item, o.qty ord_qty , i.loc, i.purch, i.qty loc_qty pick list , nvl(sum(i.qty) over ( partition by i.item order by i.purch, i.loc rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty order by s.loc41 2012-12-05 #ukoug2012 Really Using Analytic Functions
  42. 42. Picking list FIFO LOC ITEM PICK_QTY ---------- ---------- -------- Ready for operator 1-A-20 A1 18 to go picking 1-B-11 B1 3 1-B-15 B1 2 1-C-04 B1 12 2-A-02 A1 6 2-D-23 B1 142 2012-12-05 #ukoug2012 Really Using Analytic Functions
  43. 43. Picking small qty select s.loc , s.item Change pick policy , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( by changing order: select o.item, o.qty ord_qty , i.loc, i.purch, i.qty loc_qty , nvl(sum(i.qty) over ( partition by i.item Here empty small order by i.qty, i.loc -- << only line changed rows between unbounded preceding and 1 preceding quantities first to ),0) sum_prv_qty from orderline o clean out locations join inventory i on i.item = o.item where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty order by s.loc43 2012-12-05 #ukoug2012 Really Using Analytic Functions
  44. 44. Picking small qty LOC ITEM PICK_QTY ---------- ---------- -------- Lots of picks 1-A-20 A1 3 1-A-31 A1 12 1-B-11 B1 4 Will clean locations 1-B-15 B1 2 quickly for new 1-C-04 B1 11 2-D-07 A1 9 incoming goods 2-D-23 B1 144 2012-12-05 #ukoug2012 Really Using Analytic Functions
  45. 45. Picking few picks select s.loc , s.item Or policy of picking , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( as few times as select o.item, o.qty ord_qty , i.loc, i.purch, i.qty loc_qty possible , nvl(sum(i.qty) over ( partition by i.item order by i.qty desc, i.loc -- << only line changed rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty order by s.loc45 2012-12-05 #ukoug2012 Really Using Analytic Functions
  46. 46. Picking few picks LOC ITEM PICK_QTY ---------- ---------- -------- Only two picks 1-A-02 B1 18 2-A-02 A1 24 But will be at expense of leaving small quantities all over warehouse46 2012-12-05 #ukoug2012 Really Using Analytic Functions
  47. 47. Picking short route select s.loc , s.item Policy of not driving , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( to the far select o.item, o.qty ord_qty , i.loc, i.purch, i.qty loc_qty warehouse if , nvl(sum(i.qty) over ( partition by i.item possible order by i.loc -- << only line changed rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty order by s.loc47 2012-12-05 #ukoug2012 Really Using Analytic Functions
  48. 48. Picking short route LOC ITEM PICK_QTY ---------- ---------- -------- All picked in the 1-A-02 B1 18 very fist aisle in the 1-A-20 A1 18 warehouse 1-A-31 A1 648 2012-12-05 #ukoug2012 Really Using Analytic Functions
  49. 49. Picking by FIFO • SUM() by item • Ordered by purchase date • Rolling sum to find how much was picked by ”previous rows” • Filter away rows where sufficient has already been picked49 2012-12-05 #ukoug2012 Really Using Analytic Functions
  50. 50. Efficient picking route Case 350 2012-12-05 #ukoug2012 Really Using Analytic Functions
  51. 51. Picking small qty select s.loc , s.item Same data as FIFO , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( picking case select o.item, o.qty ord_qty , i.loc, i.purch, i.qty loc_qty , nvl(sum(i.qty) over ( partition by i.item But for this case we order by i.qty, i.loc -- << only line changed rows between unbounded preceding and 1 preceding will use the policy of ),0) sum_prv_qty from orderline o picking small join inventory i on i.item = o.item quantities where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty order by s.loc51 2012-12-05 #ukoug2012 Really Using Analytic Functions
  52. 52. Picking small qty LOC ITEM PICK_QTY ---------- ---------- -------- Because that gives 1-A-20 A1 3 many picks and 1-A-31 A1 12 shows this case best 1-B-11 B1 4 1-B-15 B1 2 1-C-04 B1 11 2-D-07 A1 9 Notice anything 2-D-23 B1 1 about these data?52 2012-12-05 #ukoug2012 Really Using Analytic Functions
  53. 53. Picking route • Is this a smart route to drive?53 2012-12-05 #ukoug2012 Really Using Analytic Functions
  54. 54. Better picking route • We need to change direction every other aisle54 2012-12-05 #ukoug2012 Really Using Analytic Functions
  55. 55. Decipher loc select to_number(substr(s.loc,1,1)) warehouse , substr(s.loc,3,1) aisle In this case location , , to_number(substr(s.loc,5,2)) position s.loc can be split into , s.item warehouse, aisle , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( and position simply select o.item, o.qty ord_qty , i.loc, i.purch, i.qty loc_qty , nvl(sum(i.qty) over ( by substr() partition by i.item order by i.qty, i.loc rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty order by s.loc55 2012-12-05 #ukoug2012 Really Using Analytic Functions
  56. 56. Decipher loc WAREHOUSE AISLE POSITION LOC ITEM PICK_QTY --------- ----- -------- ---------- ---------- -------- Now we can use 1 A 20 1-A-20 A1 3 analytics on the 1 A 31 1-A-31 A1 12 individual parts of 1 B 11 1-B-11 B1 4 1 B 15 1-B-15 B1 2 the location 1 C 4 1-C-04 B1 11 2 D 7 2-D-07 A1 9 2 D 23 2-D-23 B1 156 2012-12-05 #ukoug2012 Really Using Analytic Functions
  57. 57. Rank aisles select to_number(substr(s.loc,1,1)) warehouse , substr(s.loc,3,1) aisle Ordering by , dense_rank() over ( order by to_number(substr(s.loc,1,1)) -- warehouse warehouse and aisle , substr(s.loc,3,1) -- aisle ) aisle_no will give same rank , to_number(substr(s.loc,5,2)) position , s.loc to positions in same , s.item , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( aisle select o.item, o.qty ord_qty, i.loc, i.purch, i.qty loc_qty , nvl(sum(i.qty) over ( partition by i.item order by i.qty, i.loc rows between unbounded preceding and 1 preceding ),0) sum_prv_qty dense_rank() from orderline o join inventory i on i.item = o.item ensures consecutive where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty ranks order by s.loc57 2012-12-05 #ukoug2012 Really Using Analytic Functions
  58. 58. Rank aisles WAREHOUSE AISLE AISLE_NO POSITION LOC ITEM PICK_QTY --------- ----- -------- -------- ---------- ---------- -------- Now we have 1 A 1 20 1-A-20 A1 3 numbered the aisles 1 A 1 31 1-A-31 A1 12 in the order they 1 B 2 11 1-B-11 B1 4 1 B 2 15 1-B-15 B1 2 are to be visited 1 C 3 4 1-C-04 B1 11 2 D 4 7 2-D-07 A1 9 2 D 4 23 2-D-23 B1 158 2012-12-05 #ukoug2012 Really Using Analytic Functions
  59. 59. Odd up, even down select s2.warehouse, s2.aisle, s2.aisle_no, s2.position, s2.loc, s2.item, s2.pick_qty mod() and case from ( select to_number(substr(s.loc,1,1)) warehouse , substr(s.loc,3,1) aisle , dense_rank() over ( order by to_number(substr(s.loc,1,1)) -- warehouse allows us to order , substr(s.loc,3,1) -- aisle ) aisle_no , to_number(substr(s.loc,5,2)) position , s.loc, s.item , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty positive on odd from ( select o.item, o.qty ord_qty, i.loc, i.purch, i.qty loc_qty , nvl(sum(i.qty) over ( partition by i.item order by i.qty, i.loc aisles and negative rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from orderline o join inventory i on i.item = o.item on even aisles where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty ) s2 order by s2.warehouse , s2.aisle_no , case when mod(s2.aisle_no,2) = 1 then s2.position else -s2.position end59 2012-12-05 #ukoug2012 Really Using Analytic Functions
  60. 60. Odd up, even down WAREHOUSE AISLE AISLE_NO POSITION LOC ITEM PICK_QTY --------- ----- -------- -------- ---------- ---------- -------- And so aisle 1 A 1 20 1-A-20 A1 3 1-A is ascending, 1 A 1 31 1-A-31 A1 12 1-B is descending, 1 B 2 15 1-B-15 B1 2 1 B 2 11 1-B-11 B1 4 1-C is ascending, 1 C 3 4 1-C-04 B1 11 2-D is descending 2 D 4 23 2-D-23 B1 1 2 D 4 7 2-D-07 A1 960 2012-12-05 #ukoug2012 Really Using Analytic Functions
  61. 61. Single door • Direction has to ”restart” per warehouse61 2012-12-05 #ukoug2012 Really Using Analytic Functions
  62. 62. Partition warehouse select s2.warehouse, s2.aisle, s2.aisle_no, s2.position, s2.loc, s2.item, s2.pick_qty from ( select to_number(substr(s.loc,1,1)) warehouse Move the , substr(s.loc,3,1) aisle , dense_rank() over ( partition by to_number(substr(s.loc,1,1)) -- warehouse warehouse part order by ) aisle_no substr(s.loc,3,1) -- aisle from the order by to , to_number(substr(s.loc,5,2)) position , s.loc, s.item the partition by , least(s.loc_qty, s.ord_qty - s.sum_prv_qty) pick_qty from ( select o.item, o.qty ord_qty, i.loc, i.purch, i.qty loc_qty , nvl(sum(i.qty) over ( partition by i.item order by i.qty, i.loc rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from orderline o join inventory i on i.item = o.item where o.ordno = :pick_order ) s where s.sum_prv_qty < s.ord_qty ) s2 order by s2.warehouse , s2.aisle_no , case when mod(s2.aisle_no,2) = 1 then s2.position else -s2.position end62 2012-12-05 #ukoug2012 Really Using Analytic Functions
  63. 63. Partition warehouse WAREHOUSE AISLE AISLE_NO POSITION LOC ITEM PICK_QTY --------- ----- -------- -------- ---------- ---------- -------- Now the aisle_no is 1 A 1 20 1-A-20 A1 3 restarted for each 1 A 1 31 1-A-31 A1 12 warehouse, so the 1 B 2 15 1-B-15 B1 2 1 B 2 11 1-B-11 B1 4 first visited aisle of a 1 C 3 4 1-C-04 B1 11 warehouse is always 2 D 1 7 2-D-07 A1 9 odd and therefore 2 D 1 23 2-D-23 B1 1 sorted ascending63 2012-12-05 #ukoug2012 Really Using Analytic Functions
  64. 64. Efficient picking route • DENSE_RANK() to number the aisles in order visited • Order the output – ”Up” on odd aisles – ”Down” on even aisles • Partition by warehouse if door is missing64 2012-12-05 #ukoug2012 Really Using Analytic Functions
  65. 65. Picking efficiency Case 465 2012-12-05 #ukoug2012 Really Using Analytic Functions
  66. 66. Picking efficiency • How fast can operators pick items? • How much do they wait idle for totes to arrive?66 2012-12-05 #ukoug2012 Really Using Analytic Functions
  67. 67. Table create table missions ( missionid number primary key, Missions are loadunit number, everytime a tote departpos varchar2(10), (loadunit) goes from departtime date, arrivepos varchar2(10), one position to arrivetime date another position on ) the conveyor system /67 2012-12-05 #ukoug2012 Really Using Analytic Functions
  68. 68. Mission datainsert into missions values ( 35986751, 10063485, STORE, timestamp 2012-04-12 06:38:07, PLF4, timestamp 2012-04-12 08:00:03 );insert into missions values ( 35986752, 10016906, STORE, timestamp 2012-04-12 06:38:07, PLF4, timestamp 2012-04-12 08:01:41 );insert into missions values ( 35986754, 10059580, STORE, timestamp 2012-04-12 06:38:07, PLF4, timestamp 2012-04-12 08:01:09 );insert into missions values ( 35986755, 10056277, STORE, timestamp 2012-04-12 06:38:07, PLF4, timestamp 2012-04-12 08:01:16 );insert into missions values ( 35986757, 10051547, STORE, timestamp 2012-04-12 06:38:07, PLF4, timestamp 2012-04-12 08:02:40 );...2690 inserts snipped out...insert into missions values ( 35992214, 10064588, PLF4, timestamp 2012-04-12 11:13:20, STORE, timestamp 2012-04-12 11:15:12 );insert into missions values ( 35992216, 10066518, PLF4, timestamp 2012-04-12 11:13:22, STORE, timestamp 2012-04-12 11:15:30 );insert into missions values ( 35992219, 10082114, PLF4, timestamp 2012-04-12 11:13:43, STORE, timestamp 2012-04-12 11:15:35 );insert into missions values ( 35992220, 10033235, PLF4, timestamp 2012-04-12 11:13:52, STORE, timestamp 2012-04-12 11:15:50 );insert into missions values ( 35992223, 10056459, PLF4, timestamp 2012-04-12 11:14:59, STORE, timestamp 2012-04-12 11:21:03 ); 68 2012-12-05 #ukoug2012 Really Using Analytic Functions
  69. 69. Arrivals select a.arrivepos pos , a.arrivetime time All missions arriving , a.loadunit at picking stations , a.missionid PLF4 and PLF5 on from missions a where a.arrivepos in (PLF4,PLF5) April 12th after and a.arrivetime >= to_date(2012-04-12 08:00:00, 08:00 YYYY-MM-DD HH24:MI:SS) and a.arrivetime <= to_date(2012-04-12 23:59:59, YYYY-MM-DD HH24:MI:SS) order by a.arrivepos, a.arrivetime69 2012-12-05 #ukoug2012 Really Using Analytic Functions
  70. 70. Arrivals POS TIME LOADUNIT MISSIONID ---- -------- --------- --------- PLF4 08:00:03 10063485 35986751 PLF4 08:00:11 10069588 35986762 PLF4 08:01:09 10059580 35986754 ... PLF4 12:47:51 10069370 35990243 PLF4 12:47:58 10026743 35990248 PLF4 12:49:06 10013439 35990250 PLF5 08:00:00 10040198 35987250 PLF5 08:00:07 10008351 35987251 PLF5 08:00:14 10068629 35987225 ... PLF5 11:28:47 10078376 35990936 PLF5 11:28:56 10035491 35990918 PLF5 11:29:07 10010287 35991015 1453 rows selected.70 2012-12-05 #ukoug2012 Really Using Analytic Functions
  71. 71. Departures select d.departpos pos , d.departtime time All missions , d.loadunit departing from , d.missionid picking stations from missions d where d.departpos in (PLF4,PLF5) PLF4 and PLF5 on and d.departtime >= to_date(2012-04-12 08:00:00, April 12th after YYYY-MM-DD HH24:MI:SS) and d.departtime <= to_date(2012-04-12 23:59:59, 08:00 YYYY-MM-DD HH24:MI:SS) order by d.departpos, d.departtime71 2012-12-05 #ukoug2012 Really Using Analytic Functions
  72. 72. Departures POS TIME LOADUNIT MISSIONID ---- -------- --------- --------- PLF4 08:00:00 10067235 35988299 PLF4 08:00:08 10063485 35988300 PLF4 08:01:07 10069588 35988307 ... PLF4 11:13:43 10082114 35992219 PLF4 11:13:52 10033235 35992220 PLF4 11:14:59 10056459 35992223 PLF5 08:00:06 10040198 35988296 PLF5 08:00:13 10008351 35988302 PLF5 08:00:35 10068629 35988303 ... PLF5 11:08:36 10018796 35992157 PLF5 11:08:45 10058221 35992158 PLF5 11:09:00 10030575 35992159 1247 rows selected.72 2012-12-05 #ukoug2012 Really Using Analytic Functions
  73. 73. Combined events select pos, time, ad, loadunit, missionid from ( select a.arrivepos pos, a.arrivetime time, A ad, a.loadunit, a.missionid from missions a where a.arrivepos in (PLF4,PLF5) and a.arrivetime >= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) and a.arrivetime <= to_date(2012-04-12 23:59:59,YYYY-MM-DD HH24:MI:SS) union all select d.departpos pos, d.departtime time, D ad, d.loadunit, d.missionid from missions d where d.departpos in (PLF4,PLF5) and d.departtime >= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) and d.departtime <= to_date(2012-04-12 23:59:59,YYYY-MM-DD HH24:MI:SS) ) s1 order by pos, time73 2012-12-05 #ukoug2012 Really Using Analytic Functions
  74. 74. Combined events POS TIME AD LOADUNIT MISSIONID ---- -------- -- --------- --------- Arrivals and PLF4 PLF4 08:00:00 08:00:03 D A 10067235 35988299 10063485 35986751 departures joined PLF4 08:00:08 D 10063485 35988300 allows us to see the PLF4 08:00:11 A 10069588 35986762 PLF4 08:01:07 D 10069588 35988307 loadunit arriving PLF4 08:01:09 A 10059580 35986754 and a little bit later PLF4 08:01:14 D 10059580 35988308 PLF4 08:01:16 A 10056277 35986755 departing PLF4 08:01:24 D 10056277 35988309 PLF4 08:01:26 A 10081310 35986764 PLF4 08:01:39 D 10081310 35988310 PLF4 08:01:41 A 10016906 35986752 ... 2700 rows selected.74 2012-12-05 #ukoug2012 Really Using Analytic Functions
  75. 75. Lead the next event with s1 as ( select a.arrivepos pos, a.arrivetime time, from missions a A ad, a.loadunit, a.missionid The analytic where a.arrivepos in (PLF4,PLF5) and a.arrivetime >= to_date(2012-04-12 and a.arrivetime <= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) 23:59:59,YYYY-MM-DD HH24:MI:SS) function lead() gives union all select d.departpos pos, d.departtime time, from missions d D ad, d.loadunit, d.missionid for each row the where d.departpos in (PLF4,PLF5) and d.departtime >= to_date(2012-04-12 and d.departtime <= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) 23:59:59,YYYY-MM-DD HH24:MI:SS) time of the next row ) select pos , time , lead(time) over ( partition by pos order by time, missionid ) nexttime , ad , loadunit from s1 order by pos, time75 2012-12-05 #ukoug2012 Really Using Analytic Functions
  76. 76. Lead the next event POS TIME NEXTTIME AD LOADUNIT ---- -------- -------- -- --------- So on each ’D’ row PLF4 PLF4 08:00:00 08:00:03 08:00:03 08:00:08 D A 10067235 10063485 NEXTTIME is the PLF4 08:00:08 08:00:11 D 10063485 time of the PLF4 08:00:11 08:01:07 A 10069588 PLF4 08:01:07 08:01:09 D 10069588 following ’A’ row PLF4 08:01:09 08:01:14 A 10059580 PLF4 08:01:14 08:01:16 D 10059580 PLF4 08:01:16 08:01:24 A 10056277 PLF4 08:01:24 08:01:26 D 10056277 And on each ’A’ row PLF4 08:01:26 08:01:39 A 10081310 NEXTTIME is the PLF4 08:01:39 08:01:41 D 10081310 PLF4 08:01:41 08:01:57 A 10016906 time of the ... 2700 rows selected. following ’D’ row76 2012-12-05 #ukoug2012 Really Using Analytic Functions
  77. 77. Lead on with s1 as ( select a.arrivepos pos, a.arrivetime time, from missions a where a.arrivepos in (PLF4,PLF5) A ad, a.loadunit, a.missionid lead() accepts a second parameter and a.arrivetime >= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) and a.arrivetime <= to_date(2012-04-12 23:59:59,YYYY-MM-DD HH24:MI:SS) union all select d.departpos pos, d.departtime time, D ad, d.loadunit, d.missionid from missions d where d.departpos in (PLF4,PLF5) and d.departtime >= to_date(2012-04-12 and d.departtime <= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) 23:59:59,YYYY-MM-DD HH24:MI:SS) telling how many ) select pos, time rows forward the , lead(time) over ( partition by pos function should order by time, missionid ) nexttime ”look” , lead(time,2) over ( partition by pos order by time, missionid ) next2time , ad, loadunit from s1 order by pos, time77 2012-12-05 #ukoug2012 Really Using Analytic Functions
  78. 78. Lead on POS TIME NEXTTIME NEXT2TIM AD LOADUNIT ---- -------- -------- -------- -- --------- The NEXT2TIME PLF4 PLF4 08:00:00 08:00:03 08:00:03 08:00:08 08:00:08 08:00:11 D A 10067235 10063485 column ”looks” 2 PLF4 08:00:08 08:00:11 08:01:07 D 10063485 rows forward PLF4 08:00:11 08:01:07 08:01:09 A 10069588 PLF4 08:01:07 08:01:09 08:01:14 D 10069588 PLF4 08:01:09 08:01:14 08:01:16 A 10059580 PLF4 08:01:14 08:01:16 08:01:24 D 10059580 PLF4 08:01:16 08:01:24 08:01:26 A 10056277 PLF4 08:01:24 08:01:26 08:01:39 D 10056277 PLF4 08:01:26 08:01:39 08:01:41 A 10081310 PLF4 08:01:39 08:01:41 08:01:57 D 10081310 PLF4 08:01:41 08:01:57 08:01:59 A 10016906 ... 2700 rows selected.78 2012-12-05 #ukoug2012 Really Using Analytic Functions
  79. 79. Filter double lead with s1 as ( select a.arrivepos pos, a.arrivetime time, A ad, a.loadunit, a.missionid from missions a where a.arrivepos in (PLF4,PLF5) and a.arrivetime >= to_date(2012-04-12 and a.arrivetime <= to_date(2012-04-12 union all select d.departpos pos, d.departtime time, 08:00:00,YYYY-MM-DD HH24:MI:SS) 23:59:59,YYYY-MM-DD HH24:MI:SS) D ad, d.loadunit, d.missionid Since we use the double lead we now from missions d where d.departpos in (PLF4,PLF5) and d.departtime >= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) and d.departtime <= to_date(2012-04-12 23:59:59,YYYY-MM-DD HH24:MI:SS) ) select pos, time arrive, nexttime depart, next2time nextarrive, loadunit from ( have all the data select pos, time , lead(time) over ( necessary on the ’A’ partition by pos order by time, missionid rows and do not ) nexttime , lead(time,2) over ( need the ’D’ rows partition by pos order by time, missionid anymore ) next2time , ad, loadunit from s1 ) s2 where ad = A order by pos, arrive79 2012-12-05 #ukoug2012 Really Using Analytic Functions
  80. 80. Filter double lead POS ARRIVE DEPART NEXTARRI LOADUNIT ---- -------- -------- -------- --------- We can now see a tote PLF4 08:00:03 08:00:08 08:00:11 10063485 arrives 08:00:03, leaves PLF4 08:00:11 08:01:07 08:01:09 10069588 PLF4 08:01:09 08:01:14 08:01:16 10059580 again at 08:00:08, and a PLF4 08:01:16 08:01:24 08:01:26 10056277 new tote arrives at PLF4 08:01:26 08:01:39 08:01:41 10081310 PLF4 08:01:41 08:01:57 08:01:59 10016906 08:00:11 ... PLF4 10:59:47 10:59:54 10:59:56 10076144 PLF4 10:59:56 11:00:11 11:00:12 10012882 Note the tote that PLF4 11:00:12 11:00:28 11:00:29 10035898 PLF4 11:00:29 11:00:42 11:00:44 10076793 arrived 10:59:56 leaves ... after 11:00:00 1453 rows selected.80 2012-12-05 #ukoug2012 Really Using Analytic Functions
  81. 81. Pick and wait with s1 as ( ... ) select pos, arrive, depart, nextarrive Calculate pick , (depart - arrive) * 24 * 60 * 60 pickseconds , (nextarrive - depart) * 24 * 60 * 60 waitseconds seconds and wait from ( select pos, time arrive, nexttime depart, next2time nextarrive, loadunit from ( seconds select pos, time , lead(time) over ( partition by pos order by time, missionid ) nexttime , lead(time,2) over ( partition by pos order by time, missionid ) next2time , ad, loadunit from s1 ) s2 where ad = A ) s3 Filter on desired 3 where arrive >= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) and arrive <= to_date(2012-04-12 10:59:59,YYYY-MM-DD HH24:MI:SS) hour interval order by pos, arrive81 2012-12-05 #ukoug2012 Really Using Analytic Functions
  82. 82. Pick and wait POS ARRIVE DEPART NEXTARRI PICKSECONDS WAITSECONDS ---- -------- -------- -------- ----------- ----------- How fast did the PLF4 08:00:03 08:00:08 08:00:11 5 3 PLF4 08:00:11 08:01:07 08:01:09 56 2 operator pick and PLF4 08:01:09 08:01:14 08:01:16 5 2 PLF4 08:01:16 08:01:24 08:01:26 8 2 how long time did ... PLF4 08:58:08 08:58:08 09:11:36 0 808 he wait for a new PLF4 09:11:36 09:12:55 09:12:56 79 1 ... tote to arrive PLF4 10:59:47 10:59:54 10:59:56 7 2 PLF4 10:59:56 11:00:11 11:00:12 15 1 PLF5 08:00:00 08:00:06 08:00:07 6 1 PLF5 08:00:07 08:00:13 08:00:14 6 1 ... PLF5 10:57:54 10:59:58 10:59:59 124 1 PLF5 10:59:59 11:00:09 11:00:10 10 1 1155 rows selected.82 2012-12-05 #ukoug2012 Really Using Analytic Functions
  83. 83. Hourly stats with s1 as ( ... ) select , pos trunc(arrive,HH24) hour Now we can use the , , count(*) picks avg(pickseconds) secondsprpick previous select as , , sum(pickseconds)/60 minutespicked 100*sum(pickseconds)/sum(pickseconds+waitseconds) pickpct basis for some plain , avg(waitseconds) secondsprwait , sum(waitseconds)/60 minuteswaited statistics by the , 100*sum(waitseconds)/sum(pickseconds+waitseconds) waitpct , , avg(pickseconds+waitseconds) secondsprcycle sum(pickseconds+waitseconds)/60 minutestotal hour , 60 * count(*) / sum(pickseconds+waitseconds) cyclesprmin from ( select pos, arrive, depart, nextarrive , (depart - arrive) * 24 * 60 * 60 pickseconds , (nextarrive - depart) * 24 * 60 * 60 waitseconds from ( select pos, time arrive, nexttime depart, next2time nextarrive, loadunit from ( select pos, time , lead(time) over ( partition by pos order by time, missionid ) nexttime , lead(time,2) over ( partition by pos order by time, missionid ) next2time , ad, loadunit from s1 ) s2 where ad = A ) s3 where arrive >= to_date(2012-04-12 08:00:00,YYYY-MM-DD HH24:MI:SS) and arrive <= to_date(2012-04-12 10:59:59,YYYY-MM-DD HH24:MI:SS) ) s4 group by pos, trunc(arrive,HH24) order by pos, trunc(arrive,HH24)83 2012-12-05 #ukoug2012 Really Using Analytic Functions
  84. 84. Hourly stats sec sec sec cycle pr min pick pr min wait pr min pr POS HOUR PICKS pick pickd pct wait waitd pct cycle total min ----- -------- ------ ----- ------ ----- ----- ------ ----- ----- ------ ----- PLF4 08:00:00 156 20.3 52.9 73.9 7.2 18.7 26.1 27.5 71.6 2.2 PLF4 09:00:00 159 13.2 35.0 71.9 5.1 13.6 28.1 18.3 48.6 3.3 PLF4 10:00:00 165 19.8 54.5 90.8 2.0 5.5 9.2 21.8 60.0 2.8 PLF5 08:00:00 247 12.9 53.2 85.3 2.2 9.2 14.7 15.2 62.4 4.0 PLF5 09:00:00 179 15.9 47.4 82.3 3.4 10.2 17.7 19.3 57.6 3.1 PLF5 10:00:00 249 10.9 45.4 75.3 3.6 14.9 24.7 14.5 60.4 4.1 6 rows selected.84 2012-12-05 #ukoug2012 Really Using Analytic Functions
  85. 85. Picking efficiency • Log over tote missions arriving and departing the picking stations • LEAD() on mission log to find the departure following an arrival => picking time • LEAD(,2) on mission log to find the arrival following a departure => waiting time85 2012-12-05 #ukoug2012 Really Using Analytic Functions
  86. 86. Forecasting sales Case 586 2012-12-05 #ukoug2012 Really Using Analytic Functions
  87. 87. Forecasting sales• Forecast the sales of next year• But follow the trend of the item87 2012-12-05 #ukoug2012 Really Using Analytic Functions
  88. 88. Table create table sales ( item varchar2(10), Simple table of mth date, monthly sales by qty number item ) /88 2012-12-05 #ukoug2012 Really Using Analytic Functions
  89. 89. Data insert into sales values (Snowchain, date 2008-01-01, 79); insert into sales values (Snowchain, date 2008-02-01, 133); Item Snowchain insert into sales values (Snowchain, date 2008-03-01, 24); sells good in winter ... and trends up insert into sales values (Snowchain, date 2010-10-01, 1); insert into sales values (Snowchain, date 2010-11-01, 73); insert into sales values (Snowchain, date 2010-12-01, 160); insert into sales values (Sunshade , date 2008-01-01, 4); insert into sales values (Sunshade , date 2008-02-01, 6); Item Sunshade sells insert into sales values (Sunshade , date 2008-03-01, 32); ... good in summer insert into sales values (Sunshade , date 2010-10-01, 11); and trends down insert into sales values (Sunshade , date 2010-11-01, 3); insert into sales values (Sunshade , date 2010-12-01, 5);89 2012-12-05 #ukoug2012 Really Using Analytic Functions
  90. 90. Slope select sales.item Graph slope: y-axis is qty , sales.mth , sales.qty x-axis is a number with the scale of 1=a month , regr_slope( Range between gives sliding 2-year window sales.qty , extract(year from sales.mth) * 12 + extract(month from sales.mth) ) over ( partition by sales.item order by sales.mth range between interval 23 month preceding and current row ) slope from sales order by sales.item, sales.mth90 2012-12-05 #ukoug2012 Really Using Analytic Functions
  91. 91. Slope ITEM MTH QTY SLOPE ---------- ---------- ----- -------- Slope value most Snowchain 2008-01-01 79 Snowchain 2008-02-01 133 54.000 accurate for 2010 Snowchain ... 2008-03-01 24 -27.500 data where 2 year Snowchain Snowchain 2010-10-01 2010-11-01 1 73 -2.274 -2.363 sliding window Snowchain 2010-12-01 160 -.991 contains full set of Sunshade 2008-01-01 4 Sunshade 2008-02-01 6 2.000 data Sunshade 2008-03-01 32 14.000 ... Sunshade 2010-10-01 11 .217 Sunshade 2010-11-01 3 -.200 Sunshade 2010-12-01 5 -.574 72 rows selected.91 2012-12-05 #ukoug2012 Really Using Analytic Functions
  92. 92. Transpose using slope select item, mth, qty , qty + 12 * slope qty_next_year As x-axis had scale from ( of 1=a month and y- select sales.item, sales.mth, sales.qty , regr_slope( axis was qty, sales.qty , extract(year from sales.mth) * 12 + extract(month from sales.mth) multiplying slope ) over ( partition by sales.item with 12 gives how order by sales.mth range between interval 23 month preceding and current row much qty goes up or ) slope down in a year from sales ) where mth >= date 2010-01-01 order by item, mth92 2012-12-05 #ukoug2012 Really Using Analytic Functions
  93. 93. Transpose using slope ITEM MTH QTY QTY_NEXT_YEAR ---------- ---------- ----- ------------- Snowchain 2010-01-01 167 188,313043 Sunshade 2010-01-01 2 -11,617391 Snowchain 2010-02-01 247 304,855652 Sunshade 2010-02-01 8 -11,137391 Snowchain 2010-03-01 42 96,3913043 Sunshade 2010-03-01 28 9,11304348 Snowchain 2010-04-01 0 42,6991304 Sunshade 2010-04-01 26 8,86086957 Snowchain 2010-05-01 0 30,8869565 Sunshade 2010-05-01 23 9,66434783 Snowchain 2010-06-01 0 19,0747826 Sunshade 2010-06-01 46 39,1130435 Snowchain 2010-07-01 0 7,2626087 Sunshade 2010-07-01 73 79,4486957 Snowchain 2010-08-01 1 -3,4295652 Sunshade 2010-08-01 25 31,7147826 Snowchain 2010-09-01 0 -16,121739 Sunshade 2010-09-01 13 18,0504348 Snowchain 2010-10-01 1 -26,292174 Sunshade 2010-10-01 11 13,6086957 Snowchain 2010-11-01 73 44,6434783 Sunshade 2010-11-01 3 ,594782609 Snowchain 2010-12-01 160 148,109565 Sunshade 2010-12-01 5 -1,886956593 2012-12-05 #ukoug2012 Really Using Analytic Functions
  94. 94. Forecast select item , add_months(mth, 12) mth Rather than column , greatest(round(qty + 12 * slope), 0) forecast QTY_NEXT_YEAR we from ( select sales.item, sales.mth, sales.qty add a year to the , regr_slope( sales.qty month and call it a , extract(year from sales.mth) * 12 + extract(month from sales.mth) ) over ( forecast partition by sales.item order by sales.mth range between interval 23 month preceding and current row ) slope We round the from sales ) numbers and skip where mth >= date 2010-01-01 any negatives order by item, mth94 2012-12-05 #ukoug2012 Really Using Analytic Functions
  95. 95. Forecast ITEM MTH FORECAST ---------- ---------- --------- Snowchain 2011-01-01 188 Sunshade 2011-01-01 0 Snowchain 2011-02-01 305 Sunshade 2011-02-01 0 Snowchain 2011-03-01 96 Sunshade 2011-03-01 9 Snowchain 2011-04-01 43 Sunshade 2011-04-01 9 Snowchain 2011-05-01 31 Sunshade 2011-05-01 10 Snowchain 2011-06-01 19 Sunshade 2011-06-01 39 Snowchain 2011-07-01 7 Sunshade 2011-07-01 79 Snowchain 2011-08-01 0 Sunshade 2011-08-01 32 Snowchain 2011-09-01 0 Sunshade 2011-09-01 18 Snowchain 2011-10-01 0 Sunshade 2011-10-01 14 Snowchain 2011-11-01 45 Sunshade 2011-11-01 1 Snowchain 2011-12-01 148 Sunshade 2011-12-01 095 2012-12-05 #ukoug2012 Really Using Analytic Functions
  96. 96. Actual + forecast select item, mth, qty, type from ( select sales.item, sales.mth, sales.qty, Actual type UNION ALL of the from sales union all actual data and the select item , add_months(mth, 12) mth forecast data for a , greatest(round(qty + 12 * slope), 0) qty , Forecast type complete set of from ( select sales.item, sales.mth, sales.qty , regr_slope( sales data that can sales.qty , extract(year from sales.mth) * 12 + extract(month from sales.mth) ) over ( be shown in a graph partition by sales.item order by sales.mth range between interval 23 month preceding and current row ) slope from sales ) where mth >= date 2010-01-01 ) order by item, mth96 2012-12-05 #ukoug2012 Really Using Analytic Functions
  97. 97. Actual + forecast ITEM MTH QTY TYPE ---------- ---------- ----- ---------- Snowchain 2008-01-01 79 Actual Sunshade 2008-01-01 4 Actual Snowchain 2008-02-01 133 Actual Sunshade 2008-02-01 6 Actual Snowchain 2008-03-01 24 Actual Sunshade 2008-03-01 32 Actual ... ... Snowchain 2010-10-01 1 Actual Sunshade 2010-10-01 11 Actual Snowchain 2010-11-01 73 Actual Sunshade 2010-11-01 3 Actual Snowchain 2010-12-01 160 Actual Sunshade 2010-12-01 5 Actual Snowchain 2011-01-01 188 Forecast Sunshade 2011-01-01 0 Forecast Snowchain 2011-02-01 305 Forecast Sunshade 2011-02-01 0 Forecast Snowchain 2011-03-01 96 Forecast Sunshade 2011-03-01 9 Forecast ... ... Snowchain 2011-10-01 0 Forecast Sunshade 2011-10-01 14 Forecast Snowchain 2011-11-01 45 Forecast Sunshade 2011-11-01 1 Forecast Snowchain 2011-12-01 148 Forecast Sunshade 2011-12-01 0 Forecast97 2012-12-05 #ukoug2012 Really Using Analytic Functions
  98. 98. Actual + forecastData from previous slide is the graph• ”Actual” is normal lines• ”Forecast” is stapled lines98 2012-12-05 #ukoug2012 Really Using Analytic Functions
  99. 99. Forecasting sales • REGR_SLOPE() to calculate trend • RANGE window for sliding trend calculation over three years • ”Transpose” last years sales by the slope to get next years forecast99 2012-12-05 #ukoug2012 Really Using Analytic Functions
  100. 100. Forecast zero stock Case 6100 2012-12-05 #ukoug2012 Really Using Analytic Functions
  101. 101. Forecast zero stock • Fireworks sell like crazy last week of December • What hour will a store run out of stock?101 2012-12-05 #ukoug2012 Really Using Analytic Functions
  102. 102. Tables create table fw_store ( shopid varchar2(10) primary key, Stores are defined containers integer by how many ) storage containers / create table fw_sales ( shopid varchar2(10) references fw_store (shopid), Sales are hourly saleshour date, data per shop in salesnem number Net Explosive Mass ) /102 2012-12-05 #ukoug2012 Really Using Analytic Functions
  103. 103. Tables create table fw_daybudget ( shopid varchar2(10) references fw_store (shopid), Daily budget of budgetdate date, Net Explosive Mass budgetnem number per shop ) / create table fw_hourbudget ( Percentage of a hour integer, days budget percent number expected to be in ) / each hour103 2012-12-05 #ukoug2012 Really Using Analytic Functions
  104. 104. Data - store insert into fw_store values (AALBORG , 4); insert into fw_store values (GLOSTRUP , 4); insert into fw_store values (HADERSLEV, 3);104 2012-12-05 #ukoug2012 Really Using Analytic Functions
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×