Date range union

Hi!
I have a subscription system, where people can subscribe to a publication during a certain period of time. I would like to know how long a person has subscribed to any publication, so i wonder does anyone know how to perform a "date range union"? By that, i mean that a query on this data:
with test_data as (select 1 id, to_date('01-JAN-2000','DD-MON-YYYY') start_date, to_date('27-JUN-2003','DD-MON-YYYY') stop_date from dual union
select 2, to_date('05-APR-2003','DD-MON-YYYY'), to_date('04-JAN-2004','DD-MON-YYYY') from dual union
select 3, to_date('03-JUL-2002','DD-MON-YYYY'), to_date('02-JUL-2008','DD-MON-YYYY') from dual)
select * from test_data;
should produce
START_DATE STOP_DATE
01-JAN-2000 00:00:00 02-JUL-2008 00:00:00
So there can be any number of periods, and they can overlap entirely as well as "on one end".
I have solved this using PL/SQL, but would like to know if there is a SQL solution. I have also solved this with a fixed number of periods (2,3...) but not with any number.

Sorry my fault. Soon after posting I found a case when the result was wrong, so I corrected the query (added default value 1 to lag(gap,1) i.e. lag(gap,1,1)) without leaving a notice. I'm home now - no database access - but I can comment to make it easier for you.
select the_start start_date,stop_date 
  from (
-- propagating the_start value: we keep data ordered by start date
--                              we carry the value of the_start from overlap row to the non-overlap row
        select start_date,stop_date,gap,              
               case when gap = 1 and lag(gap,1) over (order by start_date) = 0
                 then lag(the_start,1) over (order by start_date)
                 else start_date
               end the_start
          from (
-- excluding intermediate overlaps: gap = 0 and the_start is null
                select start_date,stop_date,gap,the_start                 
                  from (
-- identifying start days: we keep data ordered by start date
--                         when we have the first overlap (current gap = 0, but the gap on the previous row <> 0) we record the start_date as the_start
                        select start_date,stop_date,gap,
                               case when gap = 0 and lag(gap,1,1) over (order by start_date) = 1
                                    then start_date
                               end the_start
                          from (
-- identifying period breaks: we keep data ordered by start date
--                            when the start_date on the next row is not greater than the stop_date on the current row we have an overlap
                                select start_date,stop_date,
                                       case when lead(start_date,1) over (order by start_date) <= stop_date
                                            then 0
                                            else 1
                                       end gap
                                  from test_data
                 where gap = 1 or the_start is not null
where gap = 1
order by start_dateTo check intermediate results run step by step starting from the inner query (just comment out the outer queries). I'm pretty sure LAG, not LEAD
Regards
Etbin

Similar Messages

  • Discoverer Date Range Union Query

    Hi All,
    I need your help in creating a discovere report in version 11G.
    Following Report find missing elimination account based on Transaction done in a date Range. Find out how many accounts are not defined in Elimination Account Setup. Following query gives me desired output but i am having hard time creating a discoverer report for Date Range Parameter as Date Range only applied to one side of union.
    In First Query i used decode with sysdate itself so that i can use effective_date as parameter and second side i just kept sysdate.
    PLease let me know how can i create a parameterized report for effective_date range.
    SELECT
        /*+ ORDERED
        USE_NL(jel jeh jeb cat src)
        INDEX(jel GL_JE_LINES_N1)
        INDEX(jeh GL_JE_HEADERS_U1)
        INDEX(jeb GL_JE_BATCHES_U1)
        INDEX(cat GL_JE_CATEGORIES_TL_U1)
        INDEX(src GL_JE_SOURCES_TL_U1) */
        CC.SEGMENT1
        ||'.'
        ||CC.segment2
        ||'.'
        ||CC.segment3
        ||'.'
        ||cc.segment4
        ||'.'
        || cc.segment5
        ||'.'
        || cc.segment6 Account,
        decode(sysdate,sysdate,sysdate,jel.effective_date) trx_date
      FROM gl_code_combinations cc,
        gl_je_lines jel,
        gl_je_headers jeh,
        gl_je_batches jeb,
        gl_je_categories cat,
        gl_je_sources src
      WHERE cc.CHART_OF_ACCOUNTS_ID = 50308
      AND cc.segment2              IN ('111710','201910')
      AND jel.code_combination_id   = cc.code_combination_id
      AND jel.status
        || ''                = 'P'
      AND (jel.accounted_cr != 0
      OR jel.accounted_dr   != 0)
      AND jeh.je_header_id   = jel.je_header_id
      AND jeh.actual_flag    = 'A'
      AND jeh.currency_code       != 'STAT'
      AND jeb.je_batch_id          = jeh.je_batch_id
      AND jeb.average_journal_flag = 'N'
      AND src.je_source_name       = jeh.je_source
      AND cat.je_category_name     = jeh.je_category
      and jel.effective_date between to_date('01-JAN-2011','DD-MON-RRRR') and to_date('31-MAY-2011','DD-MON-RRRR')
      MINUS
      SELECT (source_segment1
        ||'.'
        ||source_segment2
        ||'.'
        ||source_segment3
        ||'.'
        ||source_segment4
        ||'.'
        ||source_segment5
        ||'.'
        ||source_segment6) def_acnt,
        sysdate
      FROM GL_ELIM_ACCOUNTS_MAP

    Hi,
    You can use the following SQL to get the effective date into the SQL and by that create the condition in the report:
    SELECT
    CC.SEGMENT1
    ||'.'
    ||CC.segment2
    ||'.'
    ||CC.segment3
    ||'.'
    ||cc.segment4
    ||'.'
    || cc.segment5
    ||'.'
    || cc.segment6 Account,
    decode(sysdate,sysdate,sysdate,jel.effective_date) trx_date,
    jel.effective_date
    FROM gl_code_combinations cc,
    gl_je_lines jel,
    gl_je_headers jeh,
    gl_je_batches jeb,
    gl_je_categories cat,
    gl_je_sources src
    WHERE cc.CHART_OF_ACCOUNTS_ID = 50308
    AND cc.segment2 IN ('111710','201910')
    AND jel.code_combination_id = cc.code_combination_id
    AND jel.status
    || '' = 'P'
    AND (jel.accounted_cr != 0
    OR jel.accounted_dr != 0)
    AND jeh.je_header_id = jel.je_header_id
    AND jeh.actual_flag = 'A'
    AND jeh.currency_code != 'STAT'
    AND jeb.je_batch_id = jeh.je_batch_id
    AND jeb.average_journal_flag = 'N'
    AND src.je_source_name = jeh.je_source
    AND cat.je_category_name = jeh.je_category
    AND NOT EXISTS (
    SELECT 1
    FROM GL_ELIM_ACCOUNTS_MAP
    WHERE CC.SEGMENT1 = source_segment1
    AND CC.segment2 = source_segment2
    AND CC.segment3 = source_segment3
    AND cc.segment4 = source_segment4
    AND cc.segment5 = source_segment5
    AND cc.segment6 = source_segment6
    AND decode(sysdate,sysdate,sysdate,jel.effective_date) = SYSDATE
    *** I removed the hints, but if you need those get them back
    *** BTW i didn't understand the logic behind the "decode(sysdate,sysdate,sysdate,jel.effective_date)" wouldn't it always be SYSDATE???
    Tamir

  • Display of 2 rows of data for 2 different date range selection

    Hi Folks,
    I have a requirement as follows,
    User has an option of selecting 2 Date Ranges
    From and To Date and again From and To Date
    The result should display 2 different rows of data with From and To Date range selection.
    Eg:
    12/09/20008 to 03/09/2009           10 20 30 40
    23/10/2009 to  18/12/2010           40 20 10 30
    Difference                                   30 0  20 10
    % Change                                   x  y  z   q
    Thanks for your input.
    Regards,
    KJ

    You will need to use union report, and you would have fours union's in this report.
    Union - 1: Data from 1st Date Range
    Union - 2: Data from 2nd Date Range
    Union - 3: Variance Calculation
    Union - 4: Percentage Variance Calculation.
    If the date's are coming from the same field, use cast function to use the same column twice in your prompts. Apply filters on each union as needed.
    Thanks.

  • How to get top 11 values per date range

    I want to get the top 11 values by date range.
    Sample Data
    CREATE TABLE SAMPLE_DATA
        DOMAIN_NAME VARCHAR2(100),
        QTD         NUMBER,
        LOAD_DATE   DATE
    -- Insert
    BEGIN
      FOR lc IN 1..20
      LOOP
        FOR ld IN 1..30
        LOOP
          INSERT
          INTO SAMPLE_DATA VALUES
              'DM_'
              ||lc,
              round(dbms_random.value(0,1000)),
              SYSDATE-ld
        END LOOP;
      END LOOP;
    COMMIT;
    END;
    SELECT *
    FROM
      (SELECT DOMAIN_NAME,
        QTD,
        LOAD_DATE
      FROM
        (SELECT DOMAIN_NAME,
          QTD,
          LOAD_DATE
        FROM SAMPLE_DATA
        WHERE LOAD_DATE = TRUNC(SYSDATE-3)
        ORDER BY QTD DESC
      WHERE ROWNUM <=10
      UNION ALL
      SELECT 'Others' DOMAIN_NAME,
        SUM(QTD) QTD,
        LOAD_DATE
      FROM
        (SELECT DOMAIN_NAME,
          QTD,
          LOAD_DATE
        FROM
          (SELECT rownum rn,
            DOMAIN_NAME,
            QTD,
            LOAD_DATE
          FROM
            (SELECT DOMAIN_NAME,
              QTD,
              LOAD_DATE
            FROM SAMPLE_DATA
            WHERE LOAD_DATE = TRUNC(SYSDATE-3)
            ORDER BY QTD DESC
        WHERE rn > 10
      GROUP BY LOAD_DATE
    ORDER BY QTD DESC
    -- Result
    DOMAIN_NAME                 QTD                         LOAD_DATE                  
    Others                      2888                        24/03/13                   
    DM_1                        1000                        24/03/13                   
    DM_20                       933                         24/03/13                   
    DM_11                       913                         24/03/13                   
    DM_3                        743                         24/03/13                   
    DM_13                       572                         24/03/13                   
    DM_12                       568                         24/03/13                   
    DM_9                        564                         24/03/13                   
    DM_6                        505                         24/03/13                   
    DM_5                        504                         24/03/13                   
    DM_2                        480                         24/03/13    
    Please, Help me get in one query this result using a range of date.
    e.g
    using LOAD_DATE BETWEEN '24/03/13' AND '25/03/13'
    DOMAIN_NAME                 QTD                         LOAD_DATE                  
    Others                      2888                        24/03/13                   
    DM_1                        1000                        24/03/13                   
    DM_20                       933                         24/03/13                   
    DM_11                       913                         24/03/13                   
    DM_3                        743                         24/03/13                   
    DM_13                       572                         24/03/13                   
    DM_12                       568                         24/03/13                   
    DM_9                        564                         24/03/13                   
    DM_6                        505                         24/03/13                   
    DM_5                        504                         24/03/13                   
    DM_2                        480                         24/03/13                     
    Others                      1948                        25/03/13                   
    DM_1                        807                         25/03/13                   
    DM_8                        764                         25/03/13                   
    DM_7                        761                         25/03/13                   
    DM_11                       656                         25/03/13                   
    DM_18                       611                         25/03/13                   
    DM_17                       523                         25/03/13                   
    DM_14                       467                         25/03/13                   
    DM_19                       447                         25/03/13                   
    DM_15                       437                         25/03/13                   
    DM_6                        380                         25/03/13             Thank you in advance.

    I got the solution. Just sharing.
    I used analytic functions that make my job easy.
    Sample Data
    DOMAIN_NAME                 QTD                         LOAD_DATE                  
    DM_1                        807                         25/03/2013                 
    DM_1                        1000                        24/03/2013                 
    DM_2                        226                         25/03/2013                 
    DM_2                        480                         24/03/2013                 
    DM_3                        244                         25/03/2013                 
    DM_3                        743                         24/03/2013                 
    DM_4                        48                          25/03/2013                 
    DM_4                        413                         24/03/2013                 
    DM_5                        164                         25/03/2013                 
    DM_5                        504                         24/03/2013                 
    DM_6                        380                         25/03/2013                 
    DM_6                        505                         24/03/2013                 
    DM_7                        761                         25/03/2013                 
    DM_7                        212                         24/03/2013                 
    DM_8                        764                         25/03/2013                 
    DM_8                        308                         24/03/2013                 
    DM_9                        354                         25/03/2013                 
    DM_9                        564                         24/03/2013                 
    DM_10                       214                         25/03/2013                 
    DM_10                       367                         24/03/2013                 
    DM_11                       656                         25/03/2013                 
    DM_11                       913                         24/03/2013                 
    DM_12                       37                          25/03/2013                 
    DM_12                       568                         24/03/2013                 
    DM_13                       332                         25/03/2013                 
    DM_13                       572                         24/03/2013                 
    DM_14                       467                         25/03/2013                 
    DM_14                       87                          24/03/2013                 
    DM_15                       437                         25/03/2013                 
    DM_15                       450                         24/03/2013                 
    DM_16                       238                         25/03/2013                 
    DM_16                       299                         24/03/2013                 
    DM_17                       523                         25/03/2013                 
    DM_17                       143                         24/03/2013                 
    DM_18                       611                         25/03/2013                 
    DM_18                       145                         24/03/2013                 
    DM_19                       447                         25/03/2013                 
    DM_19                       464                         24/03/2013                 
    DM_20                       91                          25/03/2013                 
    DM_20                       933                         24/03/2013                  Top 11 QTD of DOMAIN_NAME per Data Range.
    SELECT *
    FROM
      (SELECT DOMAIN_NAME,
        QTD,
        LOAD_DATE
      FROM
        (SELECT LOAD_DATE,
          DOMAIN_NAME ,
          QTD,
          (DENSE_RANK() OVER (PARTITION BY LOAD_DATE ORDER BY QTD DESC )) AS RANK_QTD
        FROM SAMPLE_DATA
        WHERE trunc(load_date) BETWEEN '24/03/2013' AND '25/03/2013'
      WHERE RANK_QTD <= 10
      UNION ALL
      SELECT 'Others',
        SUM(QTD) AS QTD,
        LOAD_DATE
      FROM
        (SELECT LOAD_DATE,
          DOMAIN_NAME ,
          QTD,
          (DENSE_RANK() OVER (PARTITION BY LOAD_DATE ORDER BY QTD DESC )) AS RANK_QTD
        FROM SAMPLE_DATA
        WHERE trunc(load_date) BETWEEN '24/03/2013' AND '25/03/2013'
      WHERE RANK_QTD > 10
      GROUP BY LOAD_DATE
    ORDER BY LOAD_DATE ASC,
      QTD DESC
    DOMAIN_NAME                 QTD                         LOAD_DATE                  
    Others                      2888                        24/03/2013                 
    DM_1                        1000                        24/03/2013                 
    DM_20                       933                         24/03/2013                 
    DM_11                       913                         24/03/2013                 
    DM_3                        743                         24/03/2013                 
    DM_13                       572                         24/03/2013                 
    DM_12                       568                         24/03/2013                 
    DM_9                        564                         24/03/2013                 
    DM_6                        505                         24/03/2013                 
    DM_5                        504                         24/03/2013                 
    DM_2                        480                         24/03/2013                 
    Others                      1948                        25/03/2013                 
    DM_1                        807                         25/03/2013                 
    DM_8                        764                         25/03/2013                 
    DM_7                        761                         25/03/2013                 
    DM_11                       656                         25/03/2013                 
    DM_18                       611                         25/03/2013                 
    DM_17                       523                         25/03/2013                 
    DM_14                       467                         25/03/2013                 
    DM_19                       447                         25/03/2013                 
    DM_15                       437                         25/03/2013                 
    DM_6                        380                         25/03/2013 

  • Continious data range algorithm

    I have in my database table 2 important date columns: StartDate (Not null) and EndDate(Allowed Null).
    I want to ensure that all records in the table would always create perfect contiues date ranges with no holes inside.
    Wor example there may not be records [1-may..1-may, 3-may-...] because there would be a hole [2-may...2-may]. Holes are not allowed.
    And overlapping is not allowed, for example [1-may..1-may, 1-may-2may, 3-may-...] is not allowed because overlapping occures on day 1-may. Overlapping and holes are not allowed. But it is allowed that table has no records at all. But all DML manipulations with existing records must ensure that overlapping and holes won't occur.
    How to write such check? How to ensure that data ranges would stay continous with no holes and no overlaps?
    Oracle 11g.

    You're setting the wrong value for the start of a group when there is no (null) lagging end date. In my example I set the value to 0 when it was null as I was expecting each group to start at 1. In your case you've set the date to 1/1/1900 which isn't necessarily the day before the first start date of the group. Instead just default it to the start date - 1 to force a match...
    SQL> ed
    Wrote file afiedt.buf
      1  with t as (select 1 as id, to_date('01.04.2013', 'DD.MM.YYYY') as val1, to_date('04.04.2013', 'DD.MM.YYYY') as val2 from dual union all
      2             select 1, to_date('05.04.2013', 'DD.MM.YYYY'), to_date('06.04.2013', 'DD.MM.YYYY') from dual union all
      3             select 1, to_date('07.04.2013', 'DD.MM.YYYY'), null from dual union all
      4             select 2, to_date('01.04.2013', 'DD.MM.YYYY'), to_date('03.04.2013', 'DD.MM.YYYY') from dual union all
      5             select 2, to_date('04.04.2013', 'DD.MM.YYYY'), to_date('07.04.2013', 'DD.MM.YYYY') from dual union all
      6             select 2, to_date('09.04.2013', 'DD.MM.YYYY'), to_date('12.04.2013', 'DD.MM.YYYY') from dual union all
      7             select 2, to_date('13.04.2013', 'DD.MM.YYYY'), null from dual union all
      8             select 3, to_date('01.04.2013', 'DD.MM.YYYY'),to_date('03.04.2013', 'DD.MM.YYYY') from dual union all
      9             select 3, to_date('04.04.2013', 'DD.MM.YYYY'), null from dual union all
    10             select 4, to_date('01.04.2013', 'DD.MM.YYYY'), to_date('01.04.2013', 'DD.MM.YYYY') from dual union all
    11             select 4, to_date('01.04.2013', 'DD.MM.YYYY'), null from dual
    12            )
    13  --
    14  select id
    15        ,val1 as "start"
    16        ,val2 as "end"
    17        ,lag(val2) over (partition by id order by val1)
    18        ,case when
    19             nvl(lag(val2) over (partition by id order by val1),val1-1) != val1-1 then
    20                   'hole or overlap'
    21              else null
    22         end as chk
    23  from t
    24* order by 1, 2
    25  /
            ID start                end                  LAG(VAL2)OVER(PARTIT CHK
             1 01-APR-2013 00:00:00 04-APR-2013 00:00:00
             1 05-APR-2013 00:00:00 06-APR-2013 00:00:00 04-APR-2013 00:00:00
             1 07-APR-2013 00:00:00                      06-APR-2013 00:00:00
             2 01-APR-2013 00:00:00 03-APR-2013 00:00:00
             2 04-APR-2013 00:00:00 07-APR-2013 00:00:00 03-APR-2013 00:00:00
             2 09-APR-2013 00:00:00 12-APR-2013 00:00:00 07-APR-2013 00:00:00 hole or overlap
             2 13-APR-2013 00:00:00                      12-APR-2013 00:00:00
             3 01-APR-2013 00:00:00 03-APR-2013 00:00:00
             3 04-APR-2013 00:00:00                      03-APR-2013 00:00:00
             4 01-APR-2013 00:00:00 01-APR-2013 00:00:00
             4 01-APR-2013 00:00:00                      01-APR-2013 00:00:00 hole or overlap
    11 rows selected.

  • Date range

    Hi,
    How do I group by to have a date range count and it will sum up the letter1 that is obtained from that one month.Currently i knwo how to run it daily but summarizing by one month of teh postcodes, i am not too sure.
    This is table counters.
    Date Postcode Letter1 Letter2
    31/05/2009     810     MOM MOM
    1/01/2009     810     MOM MOM
    1/02/2009      810     MOM MOM
    29/05/2009     812     DAD DAD
    30/04/2009     832     DAD
    31/05/2009     835     DAD
    29/05/2009     812     MOM
    29/05/2009     812     MOM MOM
    DDL
    create table counters
    (DATETIME date,
    Postcode number,
    letter1 varchar2(5),
    letter 2 varchar2(5));
    Query I have tried:
    <pre>
    SELECT TO_CHAR(DATETIME, 'DD/MM/YY'),POSTCODE,
    count(letter1) as letter1_TOTAL,
    count(letter2) as letter2_TOTAL,
    sum(case when letter1 ='MOM' then 1 else 0 end) as "MOM",
    sum(case when letter2 ='DAD' then 1 else 0 end) as "DATE"
    FROM counters
    WHERE DATETIME >= (sysdate -180)
    GROUP BY TO_CHAR(DATETIME, 'DD/MM/YY'),POSTCODE
    ORDER BY TO_CHAR (DATETIME,'DD/MM/YY') DESC;
    </pre>
    Not sure how to do this month based.
    Liek my expected results should be
    Date Postcode letter1 letter2
    1/01/2009 -1/02/2009 810 2 null --------->MOM occured twice in that month
    1/03/2009 -1/04/2009 810 null null
    1/05/2009 -1/06/2009 810 1 null
    1/01/2009 -1/02/2009 812 null null
    1/03/2009 -1/04/2009 812 null null
    1/05/2009 -1/06/2009 812 1 1
    At that one month how many times MOM/DAD has summed up in that postcode.
    Edited by: CrackerJack on Jun 3, 2009 10:30 PM

    Still not very clear about our requirement.
    SQL> WITH counters AS
      2       (SELECT TO_DATE ('31/05/2009', 'DD/MM/YYYY') datetime, 810 postco
      3               'MOM' letter1, 'MOM' letter2
      4          FROM DUAL
      5        UNION ALL
      6        SELECT TO_DATE ('1/01/2009', 'DD/MM/YYYY'), 810, 'MOM', 'MOM'
      7          FROM DUAL
      8        UNION ALL
      9        SELECT TO_DATE ('1/02/2009', 'DD/MM/YYYY'), 810, 'MOM', 'MOM'
    10          FROM DUAL
    11        UNION ALL
    12        SELECT TO_DATE ('29/05/2009', 'DD/MM/YYYY'), 812, 'DAD', 'DAD'
    13          FROM DUAL
    14        UNION ALL
    15        SELECT TO_DATE ('30/04/2009', 'DD/MM/YYYY'), 832, 'DAD', NULL
    16          FROM DUAL
    17        UNION ALL
    18        SELECT TO_DATE ('31/05/2009', 'DD/MM/YYYY'), 835, 'DAD', NULL
    19          FROM DUAL
    20        UNION ALL
    21        SELECT TO_DATE ('29/05/2009', 'DD/MM/YYYY'), 812, 'MOM', NULL
    22          FROM DUAL
    23        UNION ALL
    24        SELECT TO_DATE ('29/05/2009', 'DD/MM/YYYY'), 812, 'MOM', 'MOM'
    25          FROM DUAL)
    26  SELECT * FROM COUNTERS
    27  ORDER BY datetime
    28  /
    DATETIME    POSTCODE LET LET
    01-JAN-09        810 MOM MOM
    01-FEB-09        810 MOM MOM
    30-APR-09        832 DAD
    29-MAY-09        812 MOM MOM
    29-MAY-09        812 DAD DAD
    29-MAY-09        812 MOM
    31-MAY-09        835 DAD
    31-MAY-09        810 MOM MOM
    8 rows selected.I changed your group by clause to include the date range. However if you want month wise you should understand that 01-Jan-2009 to 31-Jan 2009 is considered as one month. So the date range for one month you specified in your expected result was wrong. (01-Jan-2009 to 01-Feb-2009) .
    Hope the following code helps:
    SQL> WITH counters AS
      2       (SELECT TO_DATE ('31/05/2009', 'DD/MM/YYYY') datetime, 810 postco
      3               'MOM' letter1, 'MOM' letter2
      4          FROM DUAL
      5        UNION ALL
      6        SELECT TO_DATE ('1/01/2009', 'DD/MM/YYYY'), 810, 'MOM', 'MOM'
      7          FROM DUAL
      8        UNION ALL
      9        SELECT TO_DATE ('1/02/2009', 'DD/MM/YYYY'), 810, 'MOM', 'MOM'
    10          FROM DUAL
    11        UNION ALL
    12        SELECT TO_DATE ('29/05/2009', 'DD/MM/YYYY'), 812, 'DAD', 'DAD'
    13          FROM DUAL
    14        UNION ALL
    15        SELECT TO_DATE ('30/04/2009', 'DD/MM/YYYY'), 832, 'DAD', NULL
    16          FROM DUAL
    17        UNION ALL
    18        SELECT TO_DATE ('31/05/2009', 'DD/MM/YYYY'), 835, 'DAD', NULL
    19          FROM DUAL
    20        UNION ALL
    21        SELECT TO_DATE ('29/05/2009', 'DD/MM/YYYY'), 812, 'MOM', NULL
    22          FROM DUAL
    23        UNION ALL
    24        SELECT TO_DATE ('29/05/2009', 'DD/MM/YYYY'), 812, 'MOM', 'MOM'
    25          FROM DUAL)
    26  SELECT      TO_CHAR (TRUNC (datetime, 'MONTH'), 'DD/MM/YYYY')
    27           || '-'
    28           || TO_CHAR (LAST_DAY (datetime), 'DD/MM/YYYY') date_range,
    29           postcode, COUNT (letter1) AS letter1_total,
    30           COUNT (letter2) AS letter2_total,
    31           SUM (CASE
    32                   WHEN letter1 = 'MOM'
    33                      THEN 1
    34                   ELSE 0
    35                END) AS "MOM", SUM (CASE
    36                                       WHEN letter2 = 'DAD'
    37                                          THEN 1
    38                                       ELSE 0
    39                                    END) AS "DAD"
    40      FROM counters
    41     WHERE datetime >= (SYSDATE - 180)
    42  GROUP BY    TO_CHAR (TRUNC (datetime, 'MONTH'), 'DD/MM/YYYY')
    43           || '-'
    44           || TO_CHAR (LAST_DAY (datetime), 'DD/MM/YYYY'),
    45           postcode
    46  ORDER BY    TO_CHAR (TRUNC (datetime, 'MONTH'), 'DD/MM/YYYY')
    47           || '-'
    48           || TO_CHAR (LAST_DAY (datetime), 'DD/MM/YYYY')
    49  /
    DATE_RANGE              POSTCODE LETTER1_TOTAL LETTER2_TOTAL        MOM         DAD
    01/01/2009-31/01/2009        810             1             1          1           0
    01/02/2009-28/02/2009        810             1             1          1           0
    01/04/2009-30/04/2009        832             1             0          0           0
    01/05/2009-31/05/2009        810             1             1          1           0
    01/05/2009-31/05/2009        812             3             2          2           1
    01/05/2009-31/05/2009        835             1             0          0           0
    6 rows selected.Regards,
    Jo
    Edit: Added code tags

  • Date Range Issue

    Hi Experts,
    I have created a linked server to connect to mysql DB . The query is executing fine currently filter is based on the on going month.
    The query actually fetches the records from 2 tables User and time sheet to find how many hours the users have  .
    Now we check the Hours for a period of 10th of the current month and 10th of the upcoming month .
    So for now date range will be  between 2014/10/05 and 2014/10/06.  This logic i have implemented in the query .
    Based on the query a report is generated which is sent out every Wednesday  .Now suppose its 5th of June 2014 . 
    The query will fail because the date range is derived based upon
    where cast(t.created_on as Date) > Concat(year(now()),"-",month(now()),"-","10")
     AND cast(t.created_on as Date) <=Concat(year(now()),"-",month(now())+1,"-","10")
    Please provide with a date filter like the report runs anytime the data is not affected. Like if the report is run in the
    first week of a new month  date range should be previous month Date 10 and current month  Date 10 and if the report is run after 10th of the current month then the date range should be between 10th of current month and 10 of upcoming month . Kindly
    help
    Select * From
    OPENQUERY
    (Mysql,
    'Select
     Sum(t.hours),
     Concat(u.firstname," ",
     u.lastname) as Name
     From mysql.time_entries t
     Inner Join
     users u
     on u.id = t.user_id    
     where cast(t.created_on as Date) >
     Concat(year(now()),"-",month(now()),"-","10")
     AND
     cast(t.created_on as Date) <=Concat(year(now()),"-",month(now())+1,"-","10")
     Group By u.firstname,u.lastname
     Union all
     Select Sum(0) as hours,
     Concat(firstname," ",
     lastname) as Name
     from users
     where id not in(
     Select
     t.user_id
     From mysql.time_entries t
     Inner Join
     users u
     on u.id = t.user_id    
     where cast(t.created_on as Date) >
     Concat(year(now()),"-",month(now()),"-","10")
     AND
     cast(t.created_on as Date) <=Concat(year(now()),"-",month(now())+1,"-","10"))
     And firstname not in( "xyz")
      GRoup by firstName,lastname'
      go

    I recommend use CLOSED-OPEN dates rather than OPEN-CLOSED dates...
    Hopefully this helps with your logic:
    DECLARE @ReportDate TABLE
    [ReportDate] DATE,
    [mDay] AS DAY([ReportDate]),
    [Beg] AS DATEADD(month, CASE WHEN DAY([ReportDate]) < 10 THEN -1 ELSE 0 END, [ReportDate]),
    [End] AS DATEADD(month, CASE WHEN DAY([ReportDate]) < 10 THEN 0 ELSE 1 END, [ReportDate]),
    [ReportBeg] AS DATEADD(month, CASE WHEN DAY([ReportDate]) < 10 THEN -1 ELSE 0 END, DATEADD(day, 10 - DAY([ReportDate]), [ReportDate])),
    [ReportEnd] AS DATEADD(month, CASE WHEN DAY([ReportDate]) < 10 THEN 0 ELSE 1 END, DATEADD(day, 10 - DAY([ReportDate]) + 1, [ReportDate]))
    INSERT INTO @ReportDate(ReportDate)
    VALUES
    ('7-May-2014'),
    ('10-May-2014'),
    ('15-May-2014');
    SELECT
    CASE WHEN SYSDATETIME() >= [ReportBeg] AND SYSDATETIME() < [ReportEnd] THEN 1 ELSE 0 END
    FROM @ReportDate;

  • Assign Month within a date range (by most days in a given month)

    I have a begin and end date, sample data as such
    select to_date('01-13-12','mm-dd-yy') from_dt,
    to_date('02-23-12','mm-dd-yy') to_dt
    from dual
    union all
    select to_date('03-15-2012','mm-dd-yy') from_dt,
    to_date('04-16-2012','mm-dd-yy') to_dt
    from dual
    union all
    select to_date('05-13-2012','mm-dd-yy') from_dt,
    to_date('07-23-2012','mm-dd-yy') to_dt
    from dual
    How do I assign a month by the most days in a month within that date range? Sometimes the date range might have the exact same amount of days in a month (like 3/15/2012 has 16 days and 4/16/2012 has 16 days). In this case, I want the earlier month (march).
    So from the sample data:
    01/13/2012, 02/23/2012, February
    03/15/2012, 04/16/2012, March
    05/13/2012, 07/23/2012, June
    Thanks
    Edited by: user4422426 on Mar 1, 2012 5:15 PM

    Hi,
    Here's one way:
    WITH     cntr          AS
         SELECT     LEVEL - 1     AS n
         FROM     (
                   SELECT      1 + MAX (to_dt - from_dt)     AS max_day_cnt
                   FROM     table_x
         CONNECT BY     LEVEL     <= max_day_cnt
    ,     got_r_num     AS
         SELECT     x.from_dt, x.to_dt
         ,     TRUNC (x.from_dt + c.n, 'MONTH')     AS month
         ,     count (*)                    AS cnt
         ,     ROW_NUMBER () OVER ( PARTITION BY  from_dt, to_dt
                             ORDER BY        COUNT (*)     DESC
                             ,             TRUNC (x.from_dt + c.n, 'MONTH')
                           )     AS r_num
         FROM       cntr     c
         JOIN       table_x  x  ON  c.n  <= x.to_dt - x.from_dt
         GROUP BY  x.from_dt, x.to_dt
         ,       TRUNC (x.from_dt + c.n, 'MONTH')
    SELECT     from_dt, to_dt
    ,     TO_CHAR (month, 'Mon YYYY')     AS mon
    ,     cnt
    FROM     got_r_num
    WHERE     r_num     = 1
    ;Thanks for posting code to create the same data. Please test your code before you post it: you got the order of arguments to TO_DATE reversed.

  • Extracting a count of distinct values between two date ranges over months

    Hi All,
    I am having a bit of difficulty in figuring out the query to build a list of active campaigns over a date range.
    i.e. I have a table with campaign IDs and their start and end date details like this
    Campaign_id     Start_date     End_date
            10001     1-Jun-09     31-May-11
            10002     1-Jun-09     23-Jun-11
            30041     21-Aug-09     31-Dec-09
            20005     3-Jun-10     31-May-11
            90021     21-Nov-09     30-Nov-10
            54000     1-Jun-11     1-Dec-12
            35600     1-Mar-10     31-Mar-12 What the above data means is, for eg. the campaign 10001 is active from 1-Jun-09 to 31-May-11 i.e. for 24 months (inclusive of the month Jun-09 and May-11)
    What I need to figure out is the counts of active campaigns between a date range and display that active count at a month level (for e.g. lets say we want to see all the campaigns that were active
    between the date range '01-JUN-2007' and '30-APR-2012' ). So the partial output would be as seen below. The list would continue till december-2012
    Month    Year    Count of active campaigns
    Jan    2009    0
    Feb    2009    0
    Mar    2009    0
    Apr    2009    0
    May    2009    0
    Jun    2009    2
    Jul    2009    2
    Aug    2009    3
    Sep    2009    3
    Oct    2009    3
    Nov    2009    4
    Dec    2009    4
    Jan    2010    3
    Feb    2010    3
    Mar    2010    4
    Apr    2010    4
    Dec    2012    1 Could anybody please help me with the right query for this.
    Thanks a lot for help
    Regards
    Goldi

    set pagesize 40
    with tab as
                    select 1 id, sysdate -100 start_date, sysdate end_date from dual
                    union
                    select 1 id, sysdate -200 start_date, sysdate -150 end_date from dual
                    union
                    select 1 id, sysdate -600 start_date, sysdate - 400 end_date from dual
                    union
                    select 1 id, sysdate -300 start_date, sysdate - 150 end_date from dual
                    union
                    select 2 id, sysdate -100 start_date, sysdate-50 end_date from dual
          year_tab as
                        select
                                 add_months(min_date, level -1) m
                        from
                                select min(trunc(start_date,'YYYY')) min_date, add_months(max(trunc(end_date,'YYYY')), 12) max_date
                                from tab
                        connect by level <= months_between(max_date, min_date)
    select to_char(m,'YYYY') year_,
             to_char(m,'Month') month_,
             nvl(act, 0) act
    from   year_tab,
                select m date_,count(*)  act
                from tab, year_tab
                where m between trunc(start_date,'MM') and trunc(end_date,'MM')
                group by m
                ) month_tab
    where m = date_(+)
    order by m;
    YEAR_ MONTH_           ACT
    2010  January            0
    2010  February           0
    2010  March              0
    2010  April              0
    2010  May                0
    2010  June               0
    2010  July               0
    2010  August             0
    2010  September          1
    2010  October            1
    2010  November           1
    2010  December           1
    2011  January            1
    2011  February           1
    2011  March              1
    2011  April              0
    2011  May                0
    2011  June               0
    2011  July               1
    2011  August             1
    2011  September          1
    2011  October            2
    2011  November           2
    2011  December           2
    2012  January            2
    2012  February           2
    2012  March              2
    2012  April              1
    2012  May                1
    2012  June               0
    2012  July               0
    2012  August             0
    2012  September          0
    2012  October            0
    2012  November           0
    2012  December           0
    36 rows selected.

  • All months in date range plus running count

    Oracle 11g
    Hello all,
    Having trouble getting the following query to return proper results. Have a table with a MEMBERNO, BUSINESS_LINE, ELIGIBILITY_START_DATE, ELIGIBILITY_END_DATE.
    MEMBERNO is not unique
    BUSINESS_LINE is not either
    Start and end date are periods of time where: MEMBERNO&BUSINESS_LINE have changed
    I need to list the member number, business_line, and each month that falls within the date range beginning with eligibility_start_date & eligibility_end_date, as well as a running count of the total in that span.
    Eg.
    member, business_line, month, year, count
    1234, bus1, 01, 2001, 1
    1234, bus1, 02, 2001, 2
    1234, bus1, 03, 2001, 3
    Here is my SQL, it is not sequencing the months dates correctly and I can not figure out why. Any help is very appreciated:
    SELECT memberno,
    business_line,
    TO_CHAR (ADD_MONTHS (start_date, LEVEL - 1), 'MM') as MONTH,
    TO_CHAR (ADD_MONTHS (start_date, LEVEL - 1), 'YYYY') as YEAR,
    ROW_NUMBER () OVER (PARTITION BY key1 ORDER BY start_date ASC) as MEMBER_MONTH_COUNT
    FROM (SELECT memberno,
    business_line,
    eligibility_start_date as start_date,
    eligibility_end_date as end_date,
    member_nbr || business_line as key1
    FROM eligibility)
    CONNECT BY LEVEL <=
    MONTHS_BETWEEN (TRUNC (END_DATE, 'MM'),
    TRUNC (START_date, 'MM'))
    + 1;
    Edited by: 935047 on Jul 25, 2012 5:58 AM
    Edited by: 935047 on Jul 25, 2012 6:18 AM

    935047 wrote:
    I need to list the member number, business_line, and each month that falls within the date range beginning with eligibility_start_date & eligibility_end_date, as well as a running count of the total in that span.
    Eg.
    member, business_line, month, year, count
    1234, bus1, 01, 2001, 1
    1234, bus1, 02, 2001, 2
    1234, bus1, 03, 2001, 3I could not understand what the Running Count mean. Hence, I used Row_Number (Same as you did).
    Below query might match yours.
    with data (memb_no, bus_line, st_date, end_date) as
      select 1234, 'bus1', to_date('01-01-2001', 'MM-DD-YYYY'), to_date('06-30-2001', 'MM-DD-YYYY') from dual
      union all
      select 1234, 'bus1', to_date('07-01-2001', 'MM-DD-YYYY'), to_date('07-30-2002', 'MM-DD-YYYY') from dual
    min_max as
      select memb_no, bus_line, min(st_date) st_date, max(end_date) end_date
        from data
       group by memb_no, bus_line
    lvl as
      select level l
        from dual
      connect by level <= (select max(round(months_between(end_date, st_date))) from min_max)
    select memb_no,
           bus_line,
           to_char(add_months(st_date, l - 1), 'MM') months,
           to_char(add_months(st_date, l - 1), 'YYYY') Year,
           row_number() over (partition by memb_no, bus_line order by st_date) cnt
      from min_max cross join lvl
    order by year, months;
    ----OUTPUT------------------------
    MEMB_NO BUS_LINE MONTHS YEAR CNT
       1234 bus1     01     2001   1
       1234 bus1     02     2001  19
       1234 bus1     03     2001   3
       1234 bus1     04     2001   4
       1234 bus1     05     2001   5
       1234 bus1     06     2001   6
       1234 bus1     07     2001   7
       1234 bus1     08     2001   8
       1234 bus1     09     2001   9
       1234 bus1     10     2001  10
       1234 bus1     11     2001  11
       1234 bus1     12     2001  12
       1234 bus1     01     2002  13
       1234 bus1     02     2002  14
       1234 bus1     03     2002  15
       1234 bus1     04     2002  16
       1234 bus1     05     2002  17
       1234 bus1     06     2002  18
       1234 bus1     07     2002   2
    19 rows selected

  • Date Range as Parameter

    Hi ,
             I have a column with date range in the format 07/21/2014-07/21/2014,
            07/16/2014-07/16/2014
           07/22/2014-07/22/2014
    there will be thousands of records like this.
    In ssrs I need to pass a pramater with date range =07/16/2014-07/22/2014 then it should display all the records between those dates. I not getting the logic here how to write it.  it is pulling all the dates it is not filtering the dates right now.
    Can anybody help me on this issue..
    BALUSUSRIHARSHA

    It will be much easier if you have two columns holding the range and you pass two parameters to find out the overlapping ranges.
    select c1, ..., cn
    from T
    where @sdt <= dt2 and @edt >= dt1; -- considering the range (dt1, dt2)
    or just the exact range:
    select c1, ..., cn
    from T
    where dt1 = @sdt and dt2 = @edt; -- considering the range (dt1, dt2)
    Since you store the range in one column of character data type then you need to split the value in two, the start and end points of the range, and do the same with the parameter but this will be easier to change the report to send two parameters instead
    one.
    Search in this forum or Transact-SQL forum for a function to split a string. Here is a good reference:
    Arrays and Lists in SQL Server
    http://www.sommarskog.se/arrays-in-sql.html
    Once you have created the function, it is a matter of using the APPLY operator, pivot the range and use same predicate as in my first query.
    Here is an example but I would encorage you to change the model.
    SET NOCOUNT ON;
    USE tempdb;
    GO
    --Itzik's VATN
    CREATE FUNCTION dbo.GetNums(@n AS BIGINT) RETURNS TABLE
    AS
    RETURN
    WITH
    L0 AS(SELECT 1 AS c UNION ALL SELECT 1),
    L1 AS(SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
    L2 AS(SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
    L3 AS(SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
    L4 AS(SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
    L5 AS(SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
    Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
    SELECT TOP (@n) n FROM Nums ORDER BY n;
    GO
    --Erland's split_me
    CREATE FUNCTION dbo.inline_split_me(@param nvarchar(MAX))
    RETURNS TABLE AS
    RETURN(
    SELECT
    ROW_NUMBER() OVER(ORDER BY n) AS rn,
    LTRIM(rtrim(convert(nvarchar(4000),
    substring(@param, n,
    charindex(N'-' COLLATE Slovenian_BIN2,
    @param + convert(nvarchar(MAX), N'-'),
    n) - n)
    ))) AS Value
    FROM dbo.GetNums(LEN(@param))
    WHERE substring(convert(nvarchar(MAX), N'-') + @param, n, 1) = N'-' COLLATE Slovenian_BIN2
    GO
    DECLARE @r varchar(21) = '07/16/2014-07/22/2014';
    DECLARE @T TABLE (dt_range varchar(21));
    INSERT INTO @T (dt_range)
    VALUES
    ('07/21/2014-07/21/2014'),
    ('07/16/2014-07/16/2014'),
    ('07/22/2014-07/22/2014'),
    ('07/23/2014-07/25/2014');
    SELECT
    T.dt_range,
    R.sdt,
    R.edt,
    W.p_sdt,
    W.p_edt
    FROM
    @T AS T
    CROSS APPLY
    SELECT
    CAST([1] AS date) AS sdt,
    CAST([2] AS date) AS edt
    FROM
    dbo.inline_split_me(T.dt_range) AS A
    PIVOT
    MAX(Value)
    FOR rn IN ([1], [2])
    ) AS P
    ) AS R
    CROSS JOIN
    SELECT
    CAST([1] AS date) AS p_sdt,
    CAST([2] AS date) AS p_edt
    FROM
    dbo.inline_split_me(@r) AS A
    PIVOT
    MAX(Value)
    FOR rn IN ([1], [2])
    ) AS P
    ) AS W
    WHERE
    R.sdt <= W.p_edt
    AND R.edt >= W.p_sdt;
    GO
    DROP FUNCTION dbo.inline_split_me, dbo.GetNums;
    GO
    Notice that the last row inserted is not part of the result set because it falls outside of the parameter date range.
    AMB
    Some guidelines for posting questions...

  • Group by with date range.

    Hi,
    I am looking for effective usage of Group by against date range.
    I have a transaction table as below.
    Date            customer_no      amount_paid
    01-Dec-13     001                  500
    02-Dec-13     001                  360
    09-Dec-13     001                  200
    02-Nov-13     001                  360
    09-Nov-13     001                  200
    02-Nov-13     001                  360
    09-Oct-13     001                  200
    02-Oct-13     001                  360
    09-Oct-13     001                  200
    02-Sep-13     001                  360
    09-Sep-13     001                  200
    ............... etc.
    I would like to see sum(amount_paid) by past date ranges 1-30 days, 31-60 days, 61-90 days.
    Below are expected results.
    Customer          Duration       amount_paid
    001                    1-30             980
    001                    31-60           450
    001                    61-90          1200
    002                    1-30             300
    002                    31-60           490
    002                    61-90           320
    003                    1-30             450
    ......................etc.
    I have to group by customer no and date range (1-30, 31-60, 61-90..etc).
    Can someone help me getting query for this.
    Thanks...
    Sreeram.

    SQL> with t
      2  as
      3  (
      4  select to_date('01-Dec-13', 'dd-Mon-rr') dt, '001' customer_no, 500 amount_paid from dual
      5    union all
      6  select to_date('02-Dec-13', 'dd-Mon-rr') dt, '001' customer_no, 360 amount_paid from dual
      7    union all
      8  select to_date('09-Dec-13', 'dd-Mon-rr') dt, '001' customer_no, 200 amount_paid from dual
      9    union all
    10  select to_date('02-Nov-13', 'dd-Mon-rr') dt, '001' customer_no, 360 amount_paid from dual
    11    union all
    12  select to_date('09-Nov-13', 'dd-Mon-rr') dt, '001' customer_no, 200 amount_paid from dual
    13    union all
    14  select to_date('02-Nov-13', 'dd-Mon-rr') dt, '001' customer_no, 360 amount_paid from dual
    15    union all
    16  select to_date('09-Oct-13', 'dd-Mon-rr') dt, '001' customer_no, 200 amount_paid from dual
    17    union all
    18  select to_date('02-Oct-13', 'dd-Mon-rr') dt, '001' customer_no, 360 amount_paid from dual
    19    union all
    20  select to_date('09-Oct-13', 'dd-Mon-rr') dt, '001' customer_no, 200 amount_paid from dual
    21    union all
    22  select to_date('02-Sep-13', 'dd-Mon-rr') dt, '001' customer_no, 360 amount_paid from dual
    23    union all
    24  select to_date('09-Sep-13', 'dd-Mon-rr') dt, '001' customer_no, 200 amount_paid from dual
    25  )
    26  select customer_no
    27       , ((grp_val - 1) * 30) + 1 start_val
    28       , grp_val * 30 end_val
    29       , sum(amount_paid) amount_paid
    30    from (
    31            select dt
    32                 , customer_no
    33                 , amount_paid
    34                 , ceil(sum(dt_interval) over(partition by customer_no order by dt)/30) grp_val
    35              from (
    36                      select dt
    37                           , customer_no
    38                           , amount_paid
    39                           , nvl(dt - lag(dt) over(partition by customer_no order by dt), 1) dt_interval
    40                        from t
    41                   )
    42         )
    43   group
    44      by customer_no
    45       , grp_val
    46   order
    47      by grp_val;
    CUS  START_VAL    END_VAL AMOUNT_PAID
    001          1         30         560
    001         31         60         760
    001         61         90         920
    001         91        120        1060
    SQL>

  • Compute Date Range with SQL Statement

    I'm sure there is a way to do this in SQL, but I cannot figure it out. I can write a PL/SQL script to do it, but would prefer using a SQL Statement. My database is Oracle Database 10.2.0.4.0.
    I have a table that contains information such as the employee number, department id, and the effective date of when the person started in that department. There is data in another table that I want to update their department number in based on their effective date range. If I could figure out how to select the effective date range correctly, I can do the rest.
    I have data such as:
    EMP_ID DEPT_NO EFFECTIVE
    101 1000 1/15/2001
    101 1050 5/24/2005
    101 2010 6/8/2008
    101 1000 8/2/2010
    I want to write a SELECT statement that returns something like this where the END_DATE is the day before the EFFECTIVE date and the last record does not have an END_DATE because they are still assigned to that department. Also, the first record in the column, I don't want to select a DEPT_NO because the effective date logic was added in January 2001 so if a person started back in 1985 they could have switched departments zero to many times so I'm not going to update any data for that period:
    EMP_ID DEPT_NO EFFECTIVE END_DATE
    101 1/14/2001
    101 1000 1/15/2001 5/23/2005
    101 1050 5/24/2005 6/7/2008
    101 2010 6/8/2008 8/1/2010
    101 1000 8/2/2010
    Below is a script to create the data in a temp table that can be used to write a SELECT statement on. I have added two employee records with different dates.
    create table temp_activity
    (emp_id number(12),
    dept_no number(12),
    effective date);
    INSERT INTO temp_activity
    (EMP_ID,DEPT_NO,EFFECTIVE)
    VALUES
    (101,1000,to_date('1/15/2001','MM/DD/YYYY'))
    INSERT INTO temp_activity
    (EMP_ID,DEPT_NO,EFFECTIVE)
    VALUES
    (101,1050,to_date('5/24/2005','MM/DD/YYYY'))
    INSERT INTO temp_activity
    (EMP_ID,DEPT_NO,EFFECTIVE)
    VALUES
    (101,2010,to_date('6/8/2008','MM/DD/YYYY'))
    INSERT INTO temp_activity
    (EMP_ID,DEPT_NO,EFFECTIVE)
    VALUES
    (101,1000,to_date('8/2/2010','MM/DD/YYYY'))
    INSERT INTO temp_activity
    (EMP_ID,DEPT_NO,EFFECTIVE)
    VALUES
    (102,1040,to_date('1/15/2001','MM/DD/YYYY'))
    INSERT INTO temp_activity
    (EMP_ID,DEPT_NO,EFFECTIVE)
    VALUES
    (102,2000,to_date('6/16/2006','MM/DD/YYYY'))
    Any help is appreciated. This is probably easy, but I cannot get my brain wrapped around it.
    Thanks - mike

    select  emp_id,
            dept_no,
            effective,
            end_date
      from  (
              select  emp_id,
                      dept_no,
                      effective,
                      lead(effective) over(partition by emp_id order by effective) - 1 end_date,
                      row_number() over(partition by emp_id order by effective) rn
                from  temp_activity
             union all
              select  emp_id,
                      null dept_no,
                      null effective,
                      min(effective) - 1 end_date,
                      0 rn
                from  temp_activity
                group by emp_id
      order by emp_id,
               rn
        EMP_ID    DEPT_NO EFFECTIVE  END_DATE
           101                       01/14/2001
           101       1000 01/15/2001 05/23/2005
           101       1050 05/24/2005 06/07/2008
           101       2010 06/08/2008 08/01/2010
           101       1000 08/02/2010
           102                       01/14/2001
           102       1040 01/15/2001 06/15/2006
           102       2000 06/16/2006
    8 rows selected.
    SQL> SY.

  • Select Row immediately previous and following a date range

    I have a query which returns two values within a given date range (colA, colB). This works great. However, I also need to return (in a separate query) the entries immediately previous and following this current date range (same two values).
    I am more familiar with MySQL where the query would include an "Order by date desc limit 1" for the row previous to the original query or "Order by date asc limit 1" for the row following the original query.
    What is the best way to return these rows within Oracle?

    Hi,
    This is an example of a Top-N Query, where you want to pick N items (N=1 in this case) from the top of an ordered list.
    This problem is a little trickier, because you want to pick from two lists, the rows before the specieifed date range (in descending order) and the rows after the range.
    The easiest way might be a UNION of two separate queries, using WHERE ROWNUM = 1 in each one.
    The solution below is easier to generalize, e.g. if you want the first and last row from each department.
    WITH
    e     AS
         SELECT     empno, ename, hiredate
         ,     ROW_NUMBER () OVER
              ( ORDER BY     CASE
                             WHEN hiredate < TO_DATE ( '01-JAN-1982'
                                            , 'DD-MON-YYYY'
                                            ) -- Start of date range
                             THEN hiredate
                        END
                        DESC     NULLS LAST
              ) AS pre_num
         ,     ROW_NUMBER () OVER
              ( ORDER BY     CASE
                             WHEN hiredate > TO_DATE     ( '31-DEC-1982'
                                            , 'DD-MON-YYYY'
                                            ) -- End of date range
                             THEN hiredate
                        END
              ) AS post_num
         FROM     scott.emp
    SELECT     empno, ename, hiredate
    FROM     e
    WHERE     pre_num          = 1
    OR     post_num     = 1
    ;Results (last hire before 1982 and first hire after 1982):
         EMPNO ENAME      HIREDATE
          7788 SCOTT      19-APR-87
          7900 JAMES      03-DEC-81

  • SUM(Case how to use this structure to get average values over date range

    I am using:
    Oracle SQL Developer (3.0.04) Build MAin-04.34 Oracle Database 11g Enterprise Edition 11.2.0.1.0 - 64bit Production
    How do I use the sum function with a case structure inside.
    so I have data that looks like has an ID, date, and value. I am looking to get the 7 day average for the date range of 4/1/2013 thru 4/20/2013
    with t as (
    select 1 ID_Key,to_date('4/1/2013','mm-dd-yyyy') date_val, 10 Value_num from dual union all
    select 1 ID_key,to_date('4/2/2013','mm-dd-yyyy'), 15 from dual union all
    select 1 ID_key,to_date('4/3/2013','mm-dd-yyyy'), 20 from dual union all
    select 1 ID_key,to_date('4/5/2013','mm-dd-yyyy'), 0 from dual union all
    select 1 ID_key,to_date('4/8/2013','mm-dd-yyyy'), 12 from dual union all
    select 1 ID_key,to_date('4/9/2013','mm-dd-yyyy'), 8 from dual union all
    select 1 ID_key,to_date('4/10/2013','mm-dd-yyyy'), 6 from dual union all
    select 1 ID_key,to_date('4/12/2013','mm-dd-yyyy'), 10 from dual union all
    select 1 ID_key,to_date('4/13/2013','mm-dd-yyyy'), 0 from dual union all
    select 1 ID_key,to_date('4/14/2013','mm-dd-yyyy'), 0 from dual union all
    select 1 ID_key,to_date('4/15/2013','mm-dd-yyyy'), 10 from dual union all
    select 1 ID_key,to_date('4/16/2013','mm-dd-yyyy'), 5 from dual union all
    select 1 ID_key,to_date('4/17/2013','mm-dd-yyyy'), 2 from dual union all
    select 1 ID_key,to_date('4/20/2013','mm-dd-yyyy'), 3 from dual union all
    select 2 ID_key,to_date('4/3/2013','mm-dd-yyyy'), 12 from dual union all
    select 2 ID_key,to_date('4/5/2013','mm-dd-yyyy'), 15 from dual union all
    select 2 ID_key,to_date('4/6/2013','mm-dd-yyyy'), 5 from dual union all
    select 2 ID_key,to_date('4/7/2013','mm-dd-yyyy'), 7 from dual union all
    select 2 ID_key,to_date('4/9/2013','mm-dd-yyyy'), 10 from dual union all
    select 2 ID_key,to_date('4/11/2013','mm-dd-yyyy'), 5 from dual union all
    select 2 ID_key,to_date('4/12/2013','mm-dd-yyyy'), 0 from dual union all
    select 2 ID_key,to_date('4/13/2013','mm-dd-yyyy'), 0 from dual union all
    select 2 ID_key,to_date('4/15/2013','mm-dd-yyyy'), 6 from dual union all
    select 2 ID_key,to_date('4/16/2013','mm-dd-yyyy'), 8 from dual union all
    select 2 ID_key,to_date('4/17/2013','mm-dd-yyyy'), 0 from dual union all
    select 2 ID_key,to_date('4/18/2013','mm-dd-yyyy'), 10 from dual union all
    select 2 ID_key,to_date('4/19/2013','mm-dd-yyyy'), 5 from dual
    )**Please let me know if the table does not load.
    I would like to get the 7 day average as long as there is date for that row has enough previous dates, it not then it will return null.
    the results should look like this
    ID_Key      date_val     Value_num     7Day_Avg     7Day_Avg2
    1     4/1/2013     10          null          null
    1     4/2/2013     15          null          null
    1     4/3/2013     20          null          null
    1     4/5/2013     0          null          null
    1     4/8/2013     12          6.71          11.75
    1     4/9/2013     8          5.71          10.00
    1     4/10/2013     6          3.71          6.50
    1     4/12/2013     10          5.14          9.00
    1     4/13/2013     0          5.14          7.20
    1     4/14/2013     0          5.14          6.00
    1     4/15/2013     10          4.86          5.67
    1     4/16/2013     5          4.42          5.17
    1     4/17/2013     2          3.85          4.50
    1     4/20/2013     3          2.86          4.00
    2     4/3/2013     12          null          null
    2     4/5/2013     15          null          null
    2     4/6/2013     5          null          null
    2     4/7/2013     7          5.57          9.75
    2     4/9/2013     10          7.00          9.80
    2     4/11/2013     5          6.00          8.40
    2     4/12/2013     0          3.86          5.40
    2     4/13/2013     0          3.14          4.40
    2     4/15/2013     6          3.00          4.20
    2     4/16/2013     8          2.71          3.80
    2     4/17/2013     0          2.71          3.17
    2     4/18/2013     10          3.43          4.00
    2     4/19/2013     5          4.14          4.83As you may notice, there are gaps in the dates, so the value are then treated as zeros for the 7Day_Avg and then ignored for teh 7Day_Avg2 (not counted as number of days averaged do to no valu_num row)
    I was trying something like this to start, but getting error "missing keyword"
    select
    t.*/,
    sum(
          case
            when date_val between :day2 - 6 and :day2
            then value_num between date_val - 6 and date_val
            else null
            end
            as 7Day_avg
    form tShould I have the case structure outside the sum function?
    Any thoughts??
    Edited by: 1004407 on Jun 7, 2013 11:06 AM

    Hi,
    If you want the average of the last 7 days, including the current day, then then RANGE should be 6 PRECEDING, not 7.
    Try this:
    WITH     got_min_date_val AS
            SELECT  id_key, date_val, value_num
            ,       MIN (date_val) OVER () AS min_date_val
            FROM    t
            WHERE  date_val BETWEEN TO_DATE ('04-01-2013', 'mm-dd-yyyy')
                             AND   TO_DATE ('04-20-2013', 'mm-dd-yyyy')
    SELECT    id_key, date_val, value_num
    ,         CASE
                  WHEN  date_val >= min_date_val + 6
                  THEN  SUM (value_num) OVER ( PARTITION BY  id_key
                                               ORDER BY      date_val
                                               RANGE         6 PRECEDING
                        / 7
              END  AS avg_7_day
    ,         CASE
                  WHEN  date_val >= min_date_val + 6
                  THEN  AVG (value_num) OVER ( PARTITION BY  id_key
                                               ORDER BY      date_val
                                               RANGE         6 PRECEDING
              END   AS avg_7_day_2
    FROM      got_min_date_val
    ORDER BY  id_key
    ,         date_val
    Output:
       ID_KEY DATE_VAL   VALUE_NUM  AVG_7_DAY  AVG_7_DAY_2
             1 01-APR-13         10
             1 02-APR-13         15
             1 03-APR-13         20
             1 05-APR-13          0
             1 08-APR-13         12       6.71        11.75
             1 09-APR-13          8       5.71        10.00
             1 10-APR-13          6       3.71         6.50
             1 12-APR-13         10       5.14         9.00
             1 13-APR-13          0       5.14         7.20
             1 14-APR-13          0       5.14         6.00
             1 15-APR-13         10       4.86         5.67
             1 16-APR-13          5       4.43         5.17
             1 17-APR-13          2       3.86         4.50
             1 20-APR-13          3       2.86         4.00
             2 03-APR-13         12
             2 05-APR-13         15
             2 06-APR-13          5
             2 07-APR-13          7       5.57         9.75
             2 09-APR-13         10       7.00         9.80
             2 11-APR-13          5       6.00         8.40
             2 12-APR-13          0       3.86         5.40
             2 13-APR-13          0       3.14         4.40
             2 15-APR-13          6       3.00         4.20
             2 16-APR-13          8       2.71         3.80
             2 17-APR-13          0       2.71         3.17
             2 18-APR-13         10       3.43         4.00
             2 19-APR-13          5       4.14         4.83
    Message was edited by: FrankKulash
    Sorry; I meant to reply to OP, not to Greg

Maybe you are looking for