oracle SQL -获取给定组的最小、最大日期(包含中断日期)

yqkkidmi  于 2022-11-03  发布在  Oracle
关注(0)|答案(2)|浏览(130)

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

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菲德尔

polhcujo

polhcujo1#

不确定您想要什么...您没有按日期分区的正确数据。您的日期是唯一的,除非您的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
fcg9iug3

fcg9iug32#

在这个网站上还有很多其他的问题想要解决同样的问题。例子是herehere,这些只是我已经提供答案的问题。
这个问题有点复杂,因为要求忽略周末。这似乎是相对简单的解决,因为我将很快解释。
您的问题没有包括表中所有列的列名。我假设第一个日期是处理日期,而另一个日期对于此查询并不重要。这可能是错误的假设。
从这个问题看,如果对于工作日(星期一至星期四),第二天有匹配的行,则组将存在。对于星期五,下一个星期一需要有匹配的行。如果是星期五,则我通过添加3天来处理此问题,如果是其他情况,则添加一天。
下面显示了一个示例查询,也可以使用SQLFiddle。
希望这能解决你的问题。

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

相关问题