Finding gaps between dates in table

Is this following possible in sql...
Lets say I have a "sales" table with these fields
SalesMan, SaleDate, Amount.
and this data
John, 6/may/07,90
John, 4/may/07,330
John, 2/may/07,200
John, 9/apr/07,300
John, 5/apr/07,300
Dave, 9/jul/07,90
Dave, 8/jul/07,90
Dave, 4/jul/07,330
Dave, 2/jul/07,200
Dave, 4/jun/07,300
Dave, 2/jun/07,300
I want to ask the database "show me the third sale made by each sales man after any 2 week gap in sales"
Here's the same data again...
John, 6/may/07,90 --- I want this one
John, 4/may/07,330
John, 2/may/07,200
<2 week gap>
John, 9/apr/07,300
John, 5/apr/07,300
Dave, 9/jul/07,90
Dave, 8/jul/07,90 --- and this one
Dave, 4/jul/07,330
Dave, 2/jul/07,200
<2 week gap>
Dave, 4/jun/07,300
Dave, 2/jun/07,300
My actual problem is more complicated but this is it in its most basic form.
Any help is much appreciated.

That's easy enough using the LAG analytic funtion.
with testdata as (select 'John' name, to_date('6/may/07') sdate, 90 amount from dual
  union all select 'John', to_date('4/may/07'), 330 from dual
  union all select 'John', to_date('2/may/07'), 200 from dual
  union all select 'John', to_date('9/apr/07'), 300 from dual
  union all select 'John', to_date('5/apr/07'), 300 from dual
  union all select 'Dave', to_date('9/jul/07'), 90  from dual
  union all select 'Dave', to_date('8/jul/07'), 90  from dual
  union all select 'Dave', to_date('4/jul/07'), 330 from dual
  union all select 'Dave', to_date('2/jul/07'), 200 from dual
  union all select 'Dave', to_date('4/jun/07'), 300 from dual
  union all select 'Dave', to_date('2/jun/07'), 300 from dual
), sales_gaps AS (
  select name, sdate, amount, 
         lag(sdate,2) over (partition by name order by sdate, amount) -
         lag(sdate,3) over (partition by name order by sdate, amount) delta
  from testdata
SELECT NAME, SDATE, AMOUNT FROM SALES_GAPS WHERE DELTA >= 14
NAME SDATE                     AMOUNT                
Dave 08-JUL-2007 12:00:00      90                    
John 06-MAY-2007 12:00:00      90                    
2 rows selected

Similar Messages

  • SQL Lead & Lag to find gap between dates

    i have a table with two columns event_start and event_end :
    CREATE TABLE MYBATCHTAB
      EVENT_START  DATE                             NOT NULL,
      EVENT_END    DATE                             NOT NULL
    and my data is :
    Insert into MYBATCHTAB
       (EVENT_START, EVENT_END)
    Values
       (TO_DATE('08/12/2013 22:45:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('08/12/2013 23:55:00', 'MM/DD/YYYY HH24:MI:SS'));
    Insert into MYBATCHTAB
       (EVENT_START, EVENT_END)
    Values
       (TO_DATE('08/12/2013 15:30:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('08/12/2013 17:00:00', 'MM/DD/YYYY HH24:MI:SS'));
    Insert into MYBATCHTAB
       (EVENT_START, EVENT_END)
    Values
       (TO_DATE('08/12/2013 16:00:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('08/12/2013 17:30:00', 'MM/DD/YYYY HH24:MI:SS'));
    Insert into MYBATCHTAB
       (EVENT_START, EVENT_END)
    Values
       (TO_DATE('08/12/2013 20:00:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('08/12/2013 22:00:00', 'MM/DD/YYYY HH24:MI:SS'));
    COMMIT;
    Event Start
    Event End
    08/12/2013 15:30:00
    08/12/2013 17:00:00
    08/12/2013 16:00:00
    08/12/2013 17:30:00
    08/12/2013 20:00:00'
    08/12/2013 22:00:00
    08/12/2013 22:45:00
    08/12/2013 23:55:00
    and i want to find the first whole start - end period in this example start : 15:30 - end 17:30 (merging  record 1&2 )
    but not the third one for example not 15.30 - 22:00 or not 15.30 23:55 because there are gaps between end dates.
    how can i do this using lead&lag ? 
    I'm not sure if this is the best approach

    Maybe a baby-step solution
    select event_start,event_end
      from (select event_start,
                   case when overlap is not null
                        then case when lead(overlap,1) over (order by event_start) is not null
                                  then lead(event_end,1) over (order by event_start)
                                  when lag(overlap,1) over (order by event_start) is not null
                                  then null
                             end
                        else event_end
                   end event_end
              from (select event_start,event_end,
                           case when lead(event_start,1) over (order by event_start) <= event_end
                                  or lag(event_end,1) over (order by event_start) >= event_start
                                then 'overlap'
                           end overlap
                      from mybatchtab
    where event_end is not null
    order by event_start
    EVENT_START
    EVENT_END
    08/12/2013 15:30:00
    08/12/2013 17:30:00
    08/12/2013 20:00:00
    08/12/2013 22:00:00
    08/12/2013 22:45:00
    08/12/2013 23:55:00
    or when there can be more than two consecutive overlaps
    select event_start,
           event_end
      from (select case when lag_overlap is null
                        then event_start
                   end event_start,
                   case when coalesce(lead_overlap,lag_overlap) is null
                        then event_end
                        when lag_overlap is null and lead_overlap is not null
                        then lead(event_end) over (order by event_start)
                    end event_end
              from (select event_start,event_end,
                           case when event_start < lag(event_end) over (order by event_start)
                                then 'overlap'
                           end lag_overlap,
                           case when event_end > lead(event_start) over (order by event_start)
                                then 'overlap'
                           end lead_overlap
                      from mybatchtab
             where lead_overlap is null
                or lag_overlap is null
    where event_end is not null
       and event_end is not null
    order by event_start
    Regards
    Etbin

  • Find gap between two dates from table

    Hello All,
    I want to find gap between two dates ,if there is no gap between two dates then it should return min(eff_dt) and max(end_dt) value
    suppose below data in my item table
    item_id    eff_dt           end_dt
    10         20-jun-2012     25-jun-2012
    10         26-jun-2012     28-jun-2012 There is no gap between two rows for item 10 then it should return rows like
    item_id eff_dt end_dt
    10 20-jun-2012 28-jun-2012
    item_id    eff_dt           end_dt
    12         20-jun-2012     25-jun-2012
    12         27-jun-2012     28-jun-2012 There is gap between two rows for item 12 then it should return like
    item_id eff_dt end_dt
    12 20-jun-2012 25-jun-2012
    12 27-jun-2012 28-jun-2012
    I hv tried using below query but it giv null value for last row
    SELECT   item_id, eff_dt, end_dt, end_dt + 1 AS newd,
             LEAD (eff_dt) OVER (PARTITION BY ctry_code, co_code, item_id ORDER BY ctry_code,
              co_code, item_id) AS LEAD,
             (CASE
                 WHEN (end_dt + 1) =
                        LEAD (eff_dt) OVER (PARTITION BY ctry_code, co_code, item_id ORDER BY ctry_code,
                         co_code, item_id, eff_dt)
                    THEN '1'
                 ELSE '2'
              END
             ) AS new_num
      FROM item
       WHERE TRIM (item_id) = '802'
    ORDER BY ctry_code, co_code, item_id, eff_dtI m using oracle 10g.
    please any help is appreciate.
    Thanks.

    Use start of group method:
    with sample_table as (
                          select 10 item_id,date '2012-6-20' start_dt,date '2012-6-25' end_dt from dual union all
                          select 10,date '2012-6-26',date '2012-6-26' from dual
    select  item_id,
            min(start_dt) start_dt,
            max(end_dt) end_dt
      from  (
             select  item_id,
                     start_dt,
                     end_dt,
                     sum(start_of_group) over(partition by item_id order by start_dt) grp
               from  (
                      select  item_id,
                              start_dt,
                              end_dt,
                              case lag(end_dt) over(partition by item_id order by start_dt)
                                when start_dt - 1 then 0
                                else 1
                              end start_of_group
                        from  sample_table
      group by item_id,
               grp
      order by item_id,
               grp
       ITEM_ID START_DT  END_DT
            10 20-JUN-12 26-JUN-12
    SQL> SY.

  • How to find the deleted data in tables

    guys,
    how to find the deleted data in tables example: i want to see whether anyone deleted data in MB5B report tables like mbew, etc.,
    regards,

    Hi,
    MBEWH is actually the history table of MBEW. It will record all the changes. As I have told you earlier if you have deleted the record dirctly from the table then it will not come even in the table MBEWH
    That means no changes have been made.
    regards

  • Find difference between date

    I need to know how i can find difference between date
    like Joining date: 01-jan-2009 Today 10-jan-2010 result will be "1 year 10 days"
    I need it in Oracle forms 6i. plz help me...

    Hi,
    In oracle forms you can use
    RESULT :=
    TRUNC ((:date2 - :date1 + 1) / 365)
    || ' year and '
    || MOD (:date2 - :date1 + 1, 365)
    || ' days';
    in sql you can use
    SELECT TRUNC ((:date2 - :date1 + 1) / 365)
    || ' year and '
    || MOD (:date2 - :date1 + 1, 365)
    || ' days'
    FROM DUAL;

  • Find out missing dates in table

    Hi,
    I've a table that sould have a record for day with sales info, but for some reason there are missing dates, is there any way i could find out witch dates are missing.
    Table Example:
    sales_date | value
    2010-01-01 | 20
    2010-01-02 | 30
    2010-01-04 | 40
    The output of the query for the example above sould return only the missing date (2010-01-03).
    Thanks in advance

    How about (I wouldn't use this if your concerned about speed!)...
    WITH src_data
           AS (SELECT TO_DATE('2010-01-01', 'YYYY-MM-DD') sales_date FROM DUAL
               UNION ALL
               SELECT TO_DATE('2010-01-02', 'YYYY-MM-DD') sales_date FROM DUAL
               UNION ALL
               SELECT TO_DATE('2010-01-04', 'YYYY-MM-DD') sales_date FROM DUAL),
        date_table
           AS (SELECT     LEVEL, MAX(sales_date) - LEVEL + 1 my_date
               FROM       src_data
               CONNECT BY LEVEL <=
                             (SELECT MAX(sales_date) - MIN(sales_date) + 1
                              FROM   src_data)
               GROUP BY   LEVEL
               ORDER BY   my_date ASC)
    SELECT *
    FROM   date_table
    WHERE  NOT EXISTS (SELECT 1
                       FROM   src_data
                       WHERE  sales_date = my_date)Cheers
    Ben

  • To find the greatest date from table

    guys,
    I currently use this query to find the difference between sysdate and the oldest date in the table
    select (SYSDATE - cur_date) from comp_check
    the problem is it fives multiple records as output.
    i want to design a query that will give the difference between sysdate and the oldest date in the table(it should throw only one record as the result)
    how do i do that.
    thanks in advance

    SQL> select sysdate-min(created) from all_users
    SQL> /
    SYSDATE-MIN(CREATED)
              507,373866
    SQL> Nicolas.
    MIN usage for oldest. Correction after ennisb's remark, thanks.
    Message was edited by:
    N. Gasparotto

  • Gaps between dates Query

    Hi,
    I needed to compute the gap time between employments for my database. The problem I am running into right now is I am computing unnecessary calculations. For example,
    Employment table:
    job start date end date
    A 13-01-2000 17-09-2002
    B 25-02-2003 23-07-2004
    C 22-01-2005 15-09-2007
    My query is as follows:
    SELECT A.job as Job1, B.job as Job2, (B.Start_Date - A.End_Date) as Gap_Time
    FROM Employment A, Employment B
    WHERE A.Start_Date != B.Start_Date AND A.End_Date != B.End_Date AND A.End_Date < B.Start_Date;
    The problem is, I should only be getting the gap times between jobs (A,B) and then (B,C), but my query also computes the gap time between A and C (there shouldn't be one though because C does not directly follow job A so that wouldn't be a gap time between jobs). I've tried to mess around with the different types of joins for the FROM part of the query but still haven't been able to figure this out. Thanks.

    Look at the Analytic Functions and specifically the key words LAG and LEAD.
    There is a lot of good advice at http://asktom.oracle.com and some demos in Morgan's Library at www.psoug.org.

  • Finding Gaps In Date Range

    I was recently asked to help create a query at my company to search for date gaps in employment status history. My table data looks similar to this
    employee_id employment_status beg_date end_date
    1               Active               1990-01-01          1991-01-01
    1               Leave               1991-02-01          1993-06-03
    1               Active               1993-06-04          1995-02-01
    1               Fired               2000-06-01          2299-12-31
    So the gap im looking for would be from 1995-02-01 and 2000-06-01
    Unfortunately as well, I dont have admin access to the database in order to be able to create an index, or do any fancy PL/SQL, im pretty much limited to the most basic SQL possible.
    Any help appreciated!

    If your database supports analytic functions, the following query should give what you want.
    with sample_data as (
      select 1 employee_id, 'Active' employment_status, date '1990-01-01' beg_date, date '1991-01-01' end_date from dual union all
      select 1, 'Leave', date '1991-02-01', date '1993-06-03' from dual union all
      select 1, 'Active', date '1993-06-04', date '1995-02-01' from dual union all
      select 1, 'Fired', date '2000-06-01', date '2299-12-31' from dual
    select employee_id,
           employment_status as last_status,
           end_date as gap_lower_bound,
           next_date as gap_upper_bound,
           next_status
    from
      select t.*,
             lead(beg_date) over(partition by employee_id order by beg_date) next_date,
             lead(employment_status) over(partition by employee_id order by beg_date) next_status
      from sample_data t
    where next_date > end_date + 1
    EMPLOYEE_ID LAST_STATUS GAP_LOWER_BOUND GAP_UPPER_BOUND NEXT_STATUS
              1 Active      01/01/1991      01/02/1991      Leave
              1 Active      01/02/1995      01/06/2000      Fired
    Note #1 : the WITH clause is just there to generate some test data "on-the-fly", you can remove it and use your real table in place of SAMPLE_DATA in the main query.
    Note #2 : unless you made a typo, the gap 01/01/1991 to 01/02/1991 should also be retrieved.
    BTW, for specific questions about SQL or PL/SQL please use the {forum:id=75} forum.
    Edited by: odie_63 on 27 févr. 2011 17:16

  • User defined function to find difference between dates

    format of dtActivityStartDate/dtActivityFinishDate: 2010-09-17 14:50:51.150
    usdFuncTimeCalc (vcActivityName,dtActivityStartDate, dtActivityFinishDate) -- user defined function
    i need to calculate time elapsed for that type of activity following are the rules:
    (If Process Request is the activity)
    Working Days: Monday through Saturday
    Hours of Operation: 9AM – 5PM
    only working hours of day need to the counted like for example if it is sep 15 11 Am is dtActivityStartDate & Sep 17 is dtActivityFinishDate is 10 Am. then time elapsed is 11am to 5pm on sep 15 , 9 to 5 on sep 16 & 9 to 10 on sep 17 so total should be
    6+ 8 + 1 = 15 hours + minutes.
    format of date time: 2010-09-17 14:50:51.150
    vcActivityName = Process Request
    Don't worry about process request...

    I hv modified the code to make it more generic inorder to suit any timings (customizable) from Monday - Saturday.
    declare
      -- ** b u s i n e s s _ h o u r s **
      -- business_hours returns the number of work houts (9 am through 5 pm,
      -- Monday through Saturday) between in_start_dt and in_end_dt.
      -- If in_start_dt > in_end_dt, the results will be <= 0.
      -- Holidays are not considered.
      in_start_dt DATE := to_date('15-SEP-2010 11:00:00','DD-MON-RRRR HH24:MI:SS');
      in_end_dt   DATE := to_date('17-SEP-2010 10:00:00','DD-MON-RRRR HH24:MI:SS');
      d          NUMBER; -- Hours of either start_dt or end_dt after midnight
      end_dt     DATE := GREATEST(in_start_dt, in_end_dt); -- In case dates were in wrong order
      return_val NUMBER; -- Total number of working hours
      start_dt   DATE := LEAST(in_start_dt, in_end_dt); -- In case dates were in wrong order
      start_time number := 9;
      end_time   number := 17;
    BEGIN
      WITH all_days AS(
        SELECT start_dt + LEVEL - 1 AS a_dt
          FROM dual
        CONNECT BY LEVEL <= 1 + TRUNC(end_dt) - TRUNC(start_dt))
          --SELECT SUM(12)
           SELECT SUM(end_time-start_time)
            INTO return_val
            FROM all_days
           WHERE TO_CHAR(a_dt,'Dy','NLS_DATE_LANGUAGE = ''ENGLISH''') NOT IN ('Sun');
      dbms_output.put_line('Return_Val_1 : '||return_val);
      -- Adjust hours from start_dt, if necessary
      IF TO_CHAR(start_dt, 'Dy', 'NLS_DATE_LANGUAGE = ''ENGLISH''') NOT IN ('Sun') THEN
         -- Calculate nbr of hours passed from midnight
         d := 24 * (start_dt - TRUNC(start_dt));
         dbms_output.put_line('d:'||d);
         IF d >= end_time THEN -- d has passed 5 PM (end_time)
            -- Don't count start_dt if it has passed the closing hours
            return_val := return_val - (end_time-start_time);
            dbms_output.put_line('if-d:'||return_val);
         ELSIF d > start_time and d < end_time THEN -- d has passed 9 AM but less than 5 PM
            -- Don't count the part of start_dt which has passed the opening hours
            return_val := return_val - (d - start_time);
            dbms_output.put_line('else-d:'||return_val);
         END IF;
      END IF;
      dbms_output.put_line('');
      dbms_output.put_line('Return_Val_2 : '||return_val);
      -- Adjust hours from end_dt, if necessary
      IF TO_CHAR(end_dt, 'Dy', 'NLS_DATE_LANGUAGE = ''ENGLISH''') NOT IN ('Sun') THEN
         d := 24 * (end_dt - TRUNC(end_dt));
         dbms_output.put_line('d:'||d);
        IF d <= 9 THEN -- d < 9 AM
           -- Don't count end_dt itself
           return_val := return_val - (end_time-start_time);
           dbms_output.put_line('if-d:'||return_val);
        ELSIF d > start_time and d < end_time THEN -- d > 5 PM
          -- Don't count part of end_dt
          return_val := return_val - (end_time - d);
          dbms_output.put_line('else-d:'||return_val);
        END IF;
      END IF;
      dbms_output.put_line('');
      dbms_output.put_line('Return_Val_3 : '||return_val);
      IF in_start_dt > in_end_dt THEN
          return_val := -return_val;
      END IF;
      dbms_output.put_line('');
      dbms_output.put_line('Return_Val_4 : '||return_val);
    END;Plz note the following points of the code :
    1) You'll need to convert it a function, I just made it a declare..begin..end; block.
    2) I hv used the same timings for start & end as you hv mentioned.
    3) The 2 variables "start_time" and "end_time" take the opening & closing business hours respectively in a 24 hour format.
    4) You might want to remove the DBMS_OUTPUT ... stmts which I had added for debugging.
    It was an interesting code block to analyze ... :-)

  • How to find gaps in data?

    Hi!
    I have the following problem.
    Data:
    range_id actual_nr
    AAA 001AAA
    AAA 002AAA
    AAA 003AAA
    AAA 006AAA
    AAA 007AAA
    AAA 009AAA
    BBB 001BBB
    BBB 002BBB
    etc.
    I have to get report in the following form
    from to nr_of_rows
    001AAA 003AAA 3
    006AAA 007AAA 2
    009AAA 1
    001BBB 002BBB 2
    etc.
    As you can see if there is a gap in sequence then I have to calculate how many rows were in sequence before the gap.
    Can somebody give me some hints or even working statement?

    How's this?
    WITH
         Sample_Data
    AS
          SELECT 'AAA' range_id, '001AAA' actual_nr FROM Dual UNION ALL
          SELECT 'AAA' range_id, '002AAA' actual_nr FROM Dual UNION ALL
          SELECT 'AAA' range_id, '003AAA' actual_nr FROM Dual UNION ALL
          SELECT 'AAA' range_id, '006AAA' actual_nr FROM Dual UNION ALL
          SELECT 'AAA' range_id, '007AAA' actual_nr FROM Dual UNION ALL
          SELECT 'AAA' range_id, '009AAA' actual_nr FROM Dual UNION ALL
          SELECT 'BBB' range_id, '001BBB' actual_nr FROM Dual UNION ALL
          SELECT 'BBB' range_id, '002BBB' actual_nr FROM Dual
    SELECT
         MIN(actual_nr_start)     actual_nr_start,
         actual_nr_finish,
         MAX(Total)
    FROM
          SELECT
              range_id,
              MIN(actual_nr)     actual_nr_start,
              MAX(actual_nr)     actual_nr_finish,
              MAX(Level)     Total
          FROM
              Sample_Data
          CONNECT BY
              range_id          = PRIOR range_id
             AND     substr(actual_nr, 1, 3)     = substr(PRIOR actual_nr, 1, 3) + 1
          GROUP BY
              range_id,
              CONNECT_BY_ROOT actual_nr
    GROUP BY
         actual_nr_finish
    ORDER BY
         SubStr(actual_nr_start, -3),
         actual_nr_start;Message was edited by:
    Brian Tkatch 2
    consolidated two levels.

  • Where we find changes in data  of table

    if log the table , it records the changes made to the data in the
    table , where it stores the data.
    regards,
    Chandu

    Check the tables CDHDR, CDPOS
    CDHDR - Change Document Header table
    CDPOS - Change Document Item table
    Regards.

  • Query to find oldest man data from table

    Emp tab:
    f_name varchar2(30)
    l_name varchar2(30)
    dob date
    sex varchar2(5)
    I want to find the F_name of the oldest man born in year 1965 , who possess the "DA" in the f_name.

    How about this?
    SELECT f_name
      FROM (SELECT *
              FROM emp
             WHERE TRUNC(dob) = 1965
               AND UPPER(f_name) LIKE '%DA%'
             ORDER BY dob desc
    WHERE ROWNUM = 1       
    not tested and assuming that there are no duplicate dates. Another option would be analytic functions.
    C.

  • Data Source Tables in SAP BW 3.5

    Hello Experts,
    I am working on scenario where I need some information regarding data source present in 3.5 version.
    I have checked RSDT table but it contains data for data sources present in 7.0 version only.
    Please provide list of tables used for data soource and other objects for SAP BW 3.5 version.
    Thanks in Advance.
    Regards,
    Sachin Motgi

    Hi Sachin,
    Please find the below Data Source tables for BW 3.5
    RSTRANFIELD: Mapping of Rule Parameters, Structure Fields
    ROOSOURCE: Info about Data Sources and to see how a datasource is extracting the data
    RSOLTPSOURCE: list of DataSources by source system
    ROOSPRMS : To set the data packet size forData Source
    RODELTAM : Record mode
    RSDCUBET RSDODSOT RSDIPROIOBJT RSQISETT: for Texts
    RSDCUBE: InfoCube
    RSDODSO: DSO
    RSQISET: INFOSET
    RSDDSTAT: Statistics BW data for aggregate selection and query accounting
    Hope it helps.
    Regards,
    Raghu

  • Gap between colums

    what is the by default gap between colums in table in oracle

    This "gap" is something that the client tool introduces (or fails to introduce) for readability. In SQL*Plus, that is controlled by the COLSEP parameter.
    SQL> set colsep '   'will put three spaces between columns.
    SQL> set colsep '|'will put one vertical pipe between columns.
    I believe the default in SQL*Plus is generally to use a single space character as the column separator.
    Justin

Maybe you are looking for