【问题标题】:SQL - Get Min, Max date for a given group with break in datesSQL - 获取给定组的最小,最大日期,日期中断
【发布时间】:2013-02-19 17:29:22
【问题描述】:

我正在尝试查找带有中断处理日期的给定值的以下数据的最小和最大处理日期(请注意,周末不处理行,如果它们不希望将它们分成两个不同的集合具有相同的值)

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;

我的尝试(我知道这是错误的)

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

返回

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

我要返回的是

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

我尝试了不同的方法来查询这个,但我无法提供有效的查询。

SQL FIDDLE

【问题讨论】:

  • 抱歉,我不明白您拆分日期的理由。你能解释一下吗?我相信您正在查看 gaps-and-islands 问题,但我不能确定。
  • @ben,如果你看到数据 A 代码有 10 个值,从 01/10 到 01/11 和 01/17 到 01/18 有效,值 9 从 01/12 到 01/ 16.我想返回值的最大和最小日期,并根据这些日期在其他表中更新该值。现在从我的原始查询中,它有两个值 9,10 用于日期范围 01/12 到 01/16,这是不正确的。
  • @ben,2012 年 1 月 14 日和 15 日是周末
  • 嗯,那个周末的问题让事情变得更复杂了!

标签: sql oracle oracle11g


【解决方案1】:

不确定您想要什么...您没有按日期划分的正确数据。您的日期是唯一的,除非您的意思是您的 i_dt 必须等于 p_dt。即使您按日期而不是值进行分区,您也会像在简单选择中一样获得所有行。 在我的示例中,我按值分区。唯一值内可能只有一个最大和一个最小日期。检查输出:

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

【讨论】:

    【解决方案2】:

    本网站上还有许多其他问题旨在解决相同的问题。例如herehere,这些只是我提供的答案。

    这个问题有点复杂,因为需要忽略周末。解决起来似乎相对简单,我很快就会解释。

    您的问题并未包含表中所有列的列名。我假设第一个日期是处理日期,而另一个日期对于这个查询并不重要。这可能是错误的假设。

    从问题来看,如果在工作日(周一至周四)第二天有匹配的行,则似乎存在一个组。对于周五,下周一需要有匹配的行。如果是星期五,我会增加 3 天,或者在其他情况下增加 1 天。

    下面显示了一个示例查询和一个SQLFiddle is also available

    希望这能解决您的问题。

    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
    

    【讨论】:

      猜你喜欢
      • 2013-04-01
      • 1970-01-01
      • 2022-10-13
      • 2017-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-09
      相关资源
      最近更新 更多