Domanda

I am using Oracle 9i and have two tables with overlapping intervals:

CREATE TABLE slowdown (startdate DATE, enddate DATE, factor NUMBER);
CREATE TABLE products (prod VARCHAR2(10 BYTE) NOT NULL, STARTDATE DATE, ENDDATE DATE); -- In my usage this table is actually the result of a query and has many more rows

INSERT INTO slowdown(startdate, enddate, factor) VALUES (TO_DATE('09-SEP-2012 00:00:00', 'DD-MON-YYYY HH24:MI:SS'), TO_DATE('28-SEP-2012 00:00:00', 'DD-MON-YYYY HH24:MI:SS'), .70);
INSERT INTO slowdown(startdate, enddate, factor) VALUES (TO_DATE('23-MAR-2013 07:00:00', 'DD-MON-YYYY HH24:MI:SS'), TO_DATE('28-MAR-2013 19:00:00', 'DD-MON-YYYY HH24:MI:SS'), 0);
INSERT INTO slowdown(startdate, enddate, factor) VALUES (TO_DATE('28-MAR-2013 07:00:00', 'DD-MON-YYYY HH24:MI:SS'), TO_DATE('29-MAR-2013 07:00:00', 'DD-MON-YYYY HH24:MI:SS'), .25);

INSERT INTO products(prod, startdate, enddate) VALUES ('LOT001', TO_DATE('01-FEB-2012 13:30:00', 'DD-MON-YYYY HH24:MI:SS'), TO_DATE('05-FEB-2012 01:00:00', 'DD-MON-YYYY HH24:MI:SS'));
INSERT INTO products(prod, startdate, enddate) VALUES ('LOT001', TO_DATE('26-SEP-2012 00:00:00', 'DD-MON-YYYY HH24:MI:SS'), TO_DATE('30-SEP-2012 00:00:00', 'DD-MON-YYYY HH24:MI:SS'));
INSERT INTO products(prod, startdate, enddate) VALUES ('LOT123', TO_DATE('20-MAR-2013 11:13:45', 'DD-MON-YYYY HH24:MI:SS'), TO_DATE('28-MAR-2013 19:00:00', 'DD-MON-YYYY HH24:MI:SS'));

As you can see, an interval in products may overlap with zero or more in slowdown or vice versa. Intervals reliably do not overlap within the same table.

For each overlap xdays between products and slowdown, I need to calculate time_reduction as xdays * factor.

prod     product_startdate   product_enddate     xdays   fctr   time_reduction
LOT001   01-FEB-2012 13:30   05-FEB-2012 01:00   0       NULL   0     
LOT001   26-SEP-2012 00:00   30-SEP-2012 00:00   2       0.7    1.4
LOT123   20-MAR-2012 11:13   28-MAR-2012 19:00   0.5     0.25   0.125

Is there an SQL statement which can produce this result?

È stato utile?

Soluzione

select
   p.prod, 
   p.startdate as product_startdate,
   p.enddate as product_enddate,
   nvl(least(p.enddate, s.enddate) - greatest(p.startdate, s.startdate), 0) as xdays,
   s.factor as fctr,   
   nvl(s.factor, 0) * nvl(least(p.enddate, s.enddate) - greatest(p.startdate, s.startdate), 0) 
      as time_reduction
from 
   products p
   left join slowdown s 
      on least(p.enddate, s.enddate) - greatest(p.startdate, s.startdate) > 0

fiddle

Altri suggerimenti

you could do something like:

select prod, startdate, enddate, factor, xdays, 
       xdays * nvl(factor, 1)  time_reduction
  from (select p.*, s.factor, 
               case 
                 when s.startdate is null
                 then
                   0
                 else
                   least(p.enddate, s.enddate) - greatest(s.startdate, p.startdate)
               end xdays
          from products p, slowdown s
         where s.startdate(+) <= p.enddate
           and s.enddate(+) >= p.startdate);

fiddle: http://sqlfiddle.com/#!4/6983b/1

I'd write PL/SQL functions for each calculation and call them into my select to get the results you want. There might be a way to do this in SQL but it'll get a little ugly.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top