Copyright © 2020, Oracle and/or its affiliates
Real World Problem Solving
with SQL
Kim Berg Hansen
Oracle ACE Director
Chris Saxon
Developer Advocate
(sql-problem-solving)
2 Copyright © 2020, Oracle and/or its affiliates | Confidential: Internal/Restricted/Highly Restricted
[Date]
Chris Saxon
Developer Advocate
Chris is part of Steven Feuerstein's Oracle
Developer Advocate team and the answer
team on Ask TOM. It's his job to help you
get the best out of Oracle Database and
have fun while doing so!
About your presenters:
Kim Berg Hansen
Oracle ACE Director
Kim is an Oracle ACE Director and SQL
Evangelist. He's the author of the recent
book "Practical Oracle SQL" and SQL quiz-
master supreme on Oracle Dev Gym. When
not writing SQL he likes to drink craft beer
and read sci-fi.
It's PARTYTIME!
…who bought the fireworks?
Forecast zero stock?
How can I
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
0
100
200
300
400
500
600
700
800
0
5
10
15
20
25
30
35
40
45
9:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00
Actual sales Predicted sales
Remaining stock
Total sales
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates. blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon
for shops loop
for hours loop
… complex fn …
end loop
end loop;
5 stores
2 hours
=> not scalable!
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
Calculate Total Sales
, sum(nem.qtynem) over (
partition by nem.shopid
order by nem.hour
rows between unbounded preceding
and current row
) sumnem
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
Calculate Remaining Stock
, greatest(nem.startnem - nvl(
sum(nem.qtynem) over (
partition by nem.shopid
order by nem.hour
rows between unbounded preceding
and 1 preceding
)
,0),0) stocknem
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
select …
, max ( hour ) + numtodsinterval(
max (stocknem) keep (
dense_rank last order by hour
) / max (qtynem) keep (
dense_rank last order by hour
), 'hour'
) zerohour
where stocknem > 0
Find Zero Stock Time
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
Full SQL
with shop as (
select s.shopid
, s.containers * 250 startnem
from fw_store s
), budget as (
select db.shopid
, db.budgetdate + numtodsinterval(hb.hour,'hour') budgethour
, db.budgetnem * hb.percent / 100 budgetnem
from fw_daybudget db
cross join fw_hourbudget hb
), nem as (
select budget.shopid
, shop.startnem
, budget.budgethour hour
, case
when budget.budgethour < sysdate
then 'S'
else 'B'
end salesbudget
, case
when budget.budgethour < sysdate
then nvl(sales.salesnem,0)
else budget.budgetnem
end qtynem
from shop
join budget
on budget.shopid = shop.shopid
left outer join fw_sales sales
on sales.shopid = budget.shopid
and sales.saleshour = budget.budgethour
)
…
…
select shopid
, max(hour)
+ numtodsinterval(
max(stocknem) keep (dense_rank last order by hour)
/ max(qtynem) keep (dense_rank last order by hour)
,'hour'
) zerohour
from (
select nem.shopid
, nem.hour
, nem.salesbudget
, nem.qtynem
, sum(nem.qtynem) over (
partition by nem.shopid
order by nem.hour
rows between unbounded preceding and current row
) sumnem
, greatest(nem.startnem - nvl(
sum(nem.qtynem) over (
partition by nem.shopid
order by nem.hour
rows between unbounded preceding and 1 preceding
)
,0),0) stocknem
from nem
)
where stocknem > 0
group by shopid
order by shopid;
Time to get the drinks!
Copyright © 2020 Oracle and/or its affiliates.
Stock picking routes?
How can I find
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates.
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
select … from (
select …
, 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 order join inventory … ) s
where s.sum_prv_qty < s.ord_qty
FIFO Picking
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
select … from (
select …
, nvl(sum(i.qty) over (
partition by i.item
order by i.loc
rows between unbounded preceding
and 1 preceding
),0) sum_prv_qty
from order join inventory … ) s
where s.sum_prv_qty < s.ord_qty
Shortest Route Picking
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
select … from (
select …
, nvl(sum(i.qty) over (
partition by i.item
order by i.qty desc, i.loc
rows between unbounded preceding
and 1 preceding
),0) sum_prv_qty
from order join inventory … ) s
where s.sum_prv_qty < s.ord_qty
Least Picks
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
select … from (
select …
, 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 order join inventory … ) s
where s.sum_prv_qty < s.ord_qty
Clean out smallest quantities
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates.
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates.
1 2 3 4
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
select … from (
select …
, dense_rank() over (
order by warehouse, aisle
) aisle_no
from ( <pick query> ) s where …
) s2 order by s2.warehouse, s2.aisle_no
, case when mod(s2.aisle_no,2) = 1
then s2.position
else -s2.position
end;
Up odds, down evens
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates.
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
SLA durations
P1 => 4 hours
P2 => 8 hours
P3 => 22 hours
P4 => 44 hours
P5 => 55 hours
24 x 7
Business
hours
07:00 – 18:00,
Monday - Friday
Find ticket
breach date
Time to work
off the calories!
Ryan McGuire / Gratisography
Find consecutive rows?
How can I
RUN_DATE TIME_IN_S DISTANCE_IN_KM
01 Apr 2020 310 1
02 Apr 2020 1,600 5
03 Apr 2020 3,580 11
06 Apr 2020 1,550 5
07 Apr 2020 300 1
10 Apr 2020 280 1
13 Apr 2020 1,530 5
14 Apr 2020 295 1
15 Apr 2020 292 1
#1
#3
#2
#4
current value = previous value + 1
RUN_DATE RN RUN_DATE - RN TIME_IN_S DISTANCE_IN_KM
01 Apr 2020 1 31 Mar 2020 310 1
02 Apr 2020 2 31 Mar 2020 1,600 5
03 Apr 2020 3 31 Mar 2020 3,580 11
06 Apr 2020 4 02 Apr 2020 1,550 5
07 Apr 2020 5 02 Apr 2020 300 1
10 Apr 2020 6 04 Apr 2020 280 1
13 Apr 2020 7 06 Apr 2020 1,530 5
14 Apr 2020 8 06 Apr 2020 295 1
15 Apr 2020 9 06 Apr 2020 292 1
-
-
-
-
-
-
-
-
-
with grps as (
select run_date ,
run_date -
row_number ()
over ( order by run_date ) grp
from running_log r
)
select min ( run_date ), count (*)
from grps
group by grp
Tabibitosan Method
match_recognize (
order by run_date
measures
first ( run_date ) as start_date,
count (*) as days
pattern ( init consecutive* )
define
consecutive as
run_date = prev ( run_date ) + 1
);
Pattern Matching
Pattern variables
Regex
11
34 1
11 0 0 0
00
0
Count all children of a node?
How can I
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
select empno
, lpad(' ', (level-1)*2) || ename
, (select count(*) from emp sub
start with sub.mgr = emp.empno
connect by sub.mgr = prior sub.empno
) subs
from emp
start with mgr is null
connect by mgr = prior empno
order siblings by empno;
Connect by Subquery
11
34 1
11 0 0 0
00
0
Level 1
Level 2
Level 3
Level 4
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
with hierarchy as ( … )
select …
from hierarchy match_recognize (
order by rn
measures …
one row per match
after match skip to next row
pattern ( strt higher* )
define
higher as higher.lvl > strt.lvl
);
Pattern Matching
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
465005
55
37008
4
11.61
0.035
0
2
4
6
8
10
12
14
0
50000
100000
150000
200000
250000
300000
350000
400000
450000
500000
Consistent Gets Sorts Duration
30x slower
8455x more gets
9252x more sorts
Connect By
Match_Recognize
=>
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
Slide deck on analytic function use cases
http://bit.ly/kibeha_analytic_pptx
Slide deck on MATCH_RECOGNIZE
http://bit.ly/kibeha_patmatch4_pptx
Article on warehouse picking
http://bit.ly/kibeha_analytics_article
Article on hierarchical child count
http://bit.ly/kibeha_match_recognize_article
Further Reading
Copyright © 2020, Oracle and/or its affiliates. All rights reserved. |
asktom.oracle.com
#MakeDataGreatAgain
Ryan McGuire / Gratisography
39 Copyright © 2020, Oracle and/or its affiliates | Confidential: Internal/Restricted/Highly Restricted
[Date]

#dbhouseparty - Real World Problem Solving with SQL

  • 1.
    Copyright © 2020,Oracle and/or its affiliates Real World Problem Solving with SQL Kim Berg Hansen Oracle ACE Director Chris Saxon Developer Advocate (sql-problem-solving)
  • 2.
    2 Copyright ©2020, Oracle and/or its affiliates | Confidential: Internal/Restricted/Highly Restricted [Date] Chris Saxon Developer Advocate Chris is part of Steven Feuerstein's Oracle Developer Advocate team and the answer team on Ask TOM. It's his job to help you get the best out of Oracle Database and have fun while doing so! About your presenters: Kim Berg Hansen Oracle ACE Director Kim is an Oracle ACE Director and SQL Evangelist. He's the author of the recent book "Practical Oracle SQL" and SQL quiz- master supreme on Oracle Dev Gym. When not writing SQL he likes to drink craft beer and read sci-fi.
  • 3.
  • 4.
  • 5.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | 0 100 200 300 400 500 600 700 800 0 5 10 15 20 25 30 35 40 45 9:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 Actual sales Predicted sales Remaining stock Total sales
  • 6.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates. blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon for shops loop for hours loop … complex fn … end loop end loop; 5 stores 2 hours => not scalable!
  • 7.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | Calculate Total Sales , sum(nem.qtynem) over ( partition by nem.shopid order by nem.hour rows between unbounded preceding and current row ) sumnem
  • 8.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | Calculate Remaining Stock , greatest(nem.startnem - nvl( sum(nem.qtynem) over ( partition by nem.shopid order by nem.hour rows between unbounded preceding and 1 preceding ) ,0),0) stocknem
  • 9.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | select … , max ( hour ) + numtodsinterval( max (stocknem) keep ( dense_rank last order by hour ) / max (qtynem) keep ( dense_rank last order by hour ), 'hour' ) zerohour where stocknem > 0 Find Zero Stock Time
  • 10.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | Full SQL with shop as ( select s.shopid , s.containers * 250 startnem from fw_store s ), budget as ( select db.shopid , db.budgetdate + numtodsinterval(hb.hour,'hour') budgethour , db.budgetnem * hb.percent / 100 budgetnem from fw_daybudget db cross join fw_hourbudget hb ), nem as ( select budget.shopid , shop.startnem , budget.budgethour hour , case when budget.budgethour < sysdate then 'S' else 'B' end salesbudget , case when budget.budgethour < sysdate then nvl(sales.salesnem,0) else budget.budgetnem end qtynem from shop join budget on budget.shopid = shop.shopid left outer join fw_sales sales on sales.shopid = budget.shopid and sales.saleshour = budget.budgethour ) … … select shopid , max(hour) + numtodsinterval( max(stocknem) keep (dense_rank last order by hour) / max(qtynem) keep (dense_rank last order by hour) ,'hour' ) zerohour from ( select nem.shopid , nem.hour , nem.salesbudget , nem.qtynem , sum(nem.qtynem) over ( partition by nem.shopid order by nem.hour rows between unbounded preceding and current row ) sumnem , greatest(nem.startnem - nvl( sum(nem.qtynem) over ( partition by nem.shopid order by nem.hour rows between unbounded preceding and 1 preceding ) ,0),0) stocknem from nem ) where stocknem > 0 group by shopid order by shopid;
  • 11.
    Time to getthe drinks! Copyright © 2020 Oracle and/or its affiliates.
  • 12.
  • 13.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates.
  • 14.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | select … from ( select … , 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 order join inventory … ) s where s.sum_prv_qty < s.ord_qty FIFO Picking
  • 15.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | select … from ( select … , nvl(sum(i.qty) over ( partition by i.item order by i.loc rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from order join inventory … ) s where s.sum_prv_qty < s.ord_qty Shortest Route Picking
  • 16.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | select … from ( select … , nvl(sum(i.qty) over ( partition by i.item order by i.qty desc, i.loc rows between unbounded preceding and 1 preceding ),0) sum_prv_qty from order join inventory … ) s where s.sum_prv_qty < s.ord_qty Least Picks
  • 17.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | select … from ( select … , 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 order join inventory … ) s where s.sum_prv_qty < s.ord_qty Clean out smallest quantities
  • 18.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates.
  • 19.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates. 1 2 3 4
  • 20.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | select … from ( select … , dense_rank() over ( order by warehouse, aisle ) aisle_no from ( <pick query> ) s where … ) s2 order by s2.warehouse, s2.aisle_no , case when mod(s2.aisle_no,2) = 1 then s2.position else -s2.position end; Up odds, down evens
  • 21.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. |Copyright © 2020 Oracle and/or its affiliates.
  • 22.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | SLA durations P1 => 4 hours P2 => 8 hours P3 => 22 hours P4 => 44 hours P5 => 55 hours 24 x 7 Business hours 07:00 – 18:00, Monday - Friday Find ticket breach date
  • 23.
    Time to work offthe calories! Ryan McGuire / Gratisography
  • 24.
  • 25.
    RUN_DATE TIME_IN_S DISTANCE_IN_KM 01Apr 2020 310 1 02 Apr 2020 1,600 5 03 Apr 2020 3,580 11 06 Apr 2020 1,550 5 07 Apr 2020 300 1 10 Apr 2020 280 1 13 Apr 2020 1,530 5 14 Apr 2020 295 1 15 Apr 2020 292 1 #1 #3 #2 #4
  • 26.
    current value =previous value + 1
  • 27.
    RUN_DATE RN RUN_DATE- RN TIME_IN_S DISTANCE_IN_KM 01 Apr 2020 1 31 Mar 2020 310 1 02 Apr 2020 2 31 Mar 2020 1,600 5 03 Apr 2020 3 31 Mar 2020 3,580 11 06 Apr 2020 4 02 Apr 2020 1,550 5 07 Apr 2020 5 02 Apr 2020 300 1 10 Apr 2020 6 04 Apr 2020 280 1 13 Apr 2020 7 06 Apr 2020 1,530 5 14 Apr 2020 8 06 Apr 2020 295 1 15 Apr 2020 9 06 Apr 2020 292 1 - - - - - - - - -
  • 28.
    with grps as( select run_date , run_date - row_number () over ( order by run_date ) grp from running_log r ) select min ( run_date ), count (*) from grps group by grp Tabibitosan Method
  • 29.
    match_recognize ( order byrun_date measures first ( run_date ) as start_date, count (*) as days pattern ( init consecutive* ) define consecutive as run_date = prev ( run_date ) + 1 ); Pattern Matching Pattern variables Regex
  • 30.
    11 34 1 11 00 0 00 0
  • 31.
    Count all childrenof a node? How can I
  • 32.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | select empno , lpad(' ', (level-1)*2) || ename , (select count(*) from emp sub start with sub.mgr = emp.empno connect by sub.mgr = prior sub.empno ) subs from emp start with mgr is null connect by mgr = prior empno order siblings by empno; Connect by Subquery
  • 33.
    11 34 1 11 00 0 00 0 Level 1 Level 2 Level 3 Level 4
  • 34.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | with hierarchy as ( … ) select … from hierarchy match_recognize ( order by rn measures … one row per match after match skip to next row pattern ( strt higher* ) define higher as higher.lvl > strt.lvl ); Pattern Matching
  • 35.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | 465005 55 37008 4 11.61 0.035 0 2 4 6 8 10 12 14 0 50000 100000 150000 200000 250000 300000 350000 400000 450000 500000 Consistent Gets Sorts Duration 30x slower 8455x more gets 9252x more sorts Connect By Match_Recognize =>
  • 36.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | Slide deck on analytic function use cases http://bit.ly/kibeha_analytic_pptx Slide deck on MATCH_RECOGNIZE http://bit.ly/kibeha_patmatch4_pptx Article on warehouse picking http://bit.ly/kibeha_analytics_article Article on hierarchical child count http://bit.ly/kibeha_match_recognize_article Further Reading
  • 37.
    Copyright © 2020,Oracle and/or its affiliates. All rights reserved. | asktom.oracle.com #MakeDataGreatAgain Ryan McGuire / Gratisography
  • 38.
    39 Copyright ©2020, Oracle and/or its affiliates | Confidential: Internal/Restricted/Highly Restricted [Date]