简体   繁体   中英

SQL - Get Min, Max date for a given group with break in dates

I'm trying to find min and max process date for following data for a given value with break in process date (note that rows are not processed on weekends, i don't want to break them into two different sets if they have same value)

SELECT 1, 'A',to_date('10/01/2012','dd/mm/yyyy'), 10, to_date('11/01/2012','dd/mm/yyyy') FROm DUAL
UNION ALL SELECT 1, 'A',to_date('11/01/2012','dd/mm/yyyy'), 10, to_date('12/01/2012','dd/mm/yyyy') FROm DUAL
UNION ALL SELECT 1, 'A',to_date('12/01/2012','dd/mm/yyyy'), 9, to_date('13/01/2012','dd/mm/yyyy') FROm DUAL
UNION ALL SELECT 1, 'A',to_date('13/01/2012','dd/mm/yyyy'), 9, to_date('14/01/2012','dd/mm/yyyy') FROm DUAL
UNION ALL SELECT 1, 'A',to_date('16/01/2012','dd/mm/yyyy'), 9, to_date('17/01/2012','dd/mm/yyyy') FROm DUAL
UNION ALL SELECT 1, 'A',to_date('17/01/2012','dd/mm/yyyy'), 10, to_date('18/01/2012','dd/mm/yyyy') FROm DUAL
UNION ALL SELECT 1, 'A',to_date('18/01/2012','dd/mm/yyyy'), 10, to_date('19/01/2012','dd/mm/yyyy') FROm DUAL;

My attempt (which i know is wrong)

SELECT id, cd, value, min(p_dt) min_dt, max(p_dt) max_dt FROM T
group by id, cd, value;

This returns

ID  CD  VALUE   MIN_DT                       MAX_DT
----------------------------------------------------------------------------------
1   A   9   January, 12 2012 00:00:00+0000  January, 16 2012 00:00:00+0000
1   A   10  January, 10 2012 00:00:00+0000  January, 18 2012 00:00:00+0000

What i want to return is

ID  CD  VALUE   MIN_DT                       MAX_DT
----------------------------------------------------------------------------------
1   A   9   January, 12 2012 00:00:00+0000  January, 16 2012 00:00:00+0000
1   A   10  January, 10 2012 00:00:00+0000  January, 11 2012 00:00:00+0000
1   A   10  January, 17 2012 00:00:00+0000  January, 18 2012 00:00:00+0000

I tried different ways to query this but i couldn't come with a working query.

SQL FIDDLE

Not sure what you want... You do not have correct data to partition by dates. Your dates are unique, unless you meant that your i_dt must be equal p_dt. Even if you partition by dates instead of values you will get all rows in return as in simple select. In my example I partition by value. There could be only one max and one min date within unique value. Examine the output:

SELECT id, cd, i_dt, p_dt, value
 , To_Char(MIN(p_dt) OVER (PARTITION BY value), 'Mon, DD YYYY HH24:MI:SS') min_dt
 , To_Char(MAX(p_dt) OVER (PARTITION BY value), 'Mon, DD YYYY HH24:MI:SS') max_dt
FROM t
/

ID    CD    I_DT           P_DT    VALUE    MIN_DT                 MAX_DT
---------------------------------------------------------------------------------------
1     A    1/14/2012    1/13/2012    9    Jan, 12 2012 00:00:00    Jan, 16 2012 00:00:00
1     A    1/17/2012    1/16/2012    9    Jan, 12 2012 00:00:00    Jan, 16 2012 00:00:00
1     A    1/13/2012    1/12/2012    9    Jan, 12 2012 00:00:00    Jan, 16 2012 00:00:00
1     A    1/19/2012    1/18/2012    10   Jan, 10 2012 00:00:00    Jan, 18 2012 00:00:00
1     A    1/18/2012    1/17/2012    10   Jan, 10 2012 00:00:00    Jan, 18 2012 00:00:00
1     A    1/12/2012    1/11/2012    10   Jan, 10 2012 00:00:00    Jan, 18 2012 00:00:00
1     A    1/11/2012    1/10/2012    10   Jan, 10 2012 00:00:00    Jan, 18 2012 00:00:00

The are a number of other questions on this site looking to solve the same problem. Examples are here and here , and those are just questions that I have provided answers for.

This question is a little more complicated because of the requirement to ignore weekends. The seems to be relatively simple to solve as I will explain soon.

You question doesn't include column names for all of the columns within your table. I have assumed that the first date is the process date and the other date is not important for this query. This might be the wrong assumption.

From the question, it looks like a group will exist if, for a weekday (Mon-Thurs), there is a matching row on the next day. For a Friday, there needs to be a matching row on the following Monday. I handle this by adding 3 days if it is a Friday or one day in every other case.

An example query is shown below and a SQLFiddle is also available .

Hopefully this solves your problem.

with test_data as (
    SELECT 1 as id, 'A' as cd,to_date('10/01/2012','dd/mm/yyyy') as p_date, 10 as value, to_date('11/01/2012','dd/mm/yyyy') as some_other_date FROm DUAL UNION ALL 
    SELECT 1 as id, 'A' as cd,to_date('11/01/2012','dd/mm/yyyy') as p_date, 10 as value, to_date('12/01/2012','dd/mm/yyyy') as some_other_date FROm DUAL UNION ALL 
    SELECT 1 as id, 'A' as cd,to_date('12/01/2012','dd/mm/yyyy') as p_date, 9 as value, to_date('13/01/2012','dd/mm/yyyy') as some_other_date FROm DUAL UNION ALL 
    SELECT 1 as id, 'A' as cd,to_date('13/01/2012','dd/mm/yyyy') as p_date, 9 as value, to_date('14/01/2012','dd/mm/yyyy') as some_other_date FROm DUAL UNION ALL 
    SELECT 1 as id, 'A' as cd,to_date('16/01/2012','dd/mm/yyyy') as p_date, 9 as value, to_date('17/01/2012','dd/mm/yyyy') as some_other_date FROm DUAL UNION ALL 
    SELECT 1 as id, 'A' as cd,to_date('17/01/2012','dd/mm/yyyy') as p_date, 10 as value, to_date('18/01/2012','dd/mm/yyyy') as some_other_date FROm DUAL UNION ALL 
    SELECT 1 as id, 'A' as cd,to_date('18/01/2012','dd/mm/yyyy') as p_date, 10 as value, to_date('19/01/2012','dd/mm/yyyy') as some_other_date FROm DUAL
)
select 
  id,
  cd,
  value,
  block_num,
  min(p_date) as process_start_date,
  max(p_date) as process_end_date
from (
    select
      id,
      cd,
      value,
      p_date,
      sum(is_block_start) over (partition by id, cd, value order by p_date) as block_num
    from (
        select
          id, 
          cd, 
          value,
          p_date,
          -- get end date of previous block       
          case when lag(case when to_char(p_date, 'DY') = 'FRI' then p_date+3 else p_date+1 end) 
            over (partition by id, cd, value order by p_date) = p_date then 0 else 1 end as is_block_start
        from test_data
        -- Make sure that the data definitely doesn't include Sat or Sun because this could just confuse things
        where to_char(p_date, 'DY') not in ('SAT', 'SUN')
    )
)
group by id, cd, value, block_num
order by id, cd, value, block_num

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM