Oracle动态范围

时间:2017-01-26 12:41:57

标签: sql oracle

所以,我有这个样本数据:

Department |     InitialDate     |     FinalDate
-------------------------------------------------------
1          | 01/01/2017 01:12:00 | 01/03/2017 00:00:08
1          | 01/03/2017 00:00:08 | 01/04/2017 05:00:01
1          | 01/04/2017 05:00:01 | 01/05/2017 02:00:00
2          | 01/05/2017 10:00:00 | 01/06/2017 11:00:08
2          | 01/06/2017 11:00:08 | 01/07/2017 04:04:00
3          | 01/07/2017 04:00:00 | 01/07/2017 15:00:22
1          | 01/07/2017 14:00:00 | 01/07/2017 18:00:08
1          | 01/07/2017 18:15:00 | 01/08/2017 22:00:00
3          | 01/12/2017 01:30:03 | 01/12/2017 18:00:00
1          | 01/13/2017 23:12:00 | 01/13/2017 23:59:08

并希望像这样分组

Department |     InitialDate     |     FinalDate
-------------------------------------------------------
1          | 01/01/2017 01:12:00 | 01/05/2017 02:00:00
2          | 01/05/2017 10:00:00 | 01/07/2017 04:04:00
3          | 01/07/2017 04:00:00 | 01/07/2017 15:00:22
1          | 01/07/2017 14:00:00 | 01/08/2017 22:00:00
3          | 01/12/2017 01:30:03 | 01/12/2017 18:00:00
1          | 01/13/2017 23:12:00 | 01/13/2017 23:59:08

我需要按部门制作小组并获取每个小组的第一个和最后一个日期,但部门可以重复,并且每次发生时,我都想要该特定窗口的第一个和最后一个日期。我已经尝试过分析功能,但似乎没有任何效果。

3 个答案:

答案 0 :(得分:1)

您可以使用LAG分析函数将每行与前一行进行比较:

SELECT department,
       MIN( InitialDate ) AS InitialDate,
       MIN( FinalDate   ) AS FinalDate
FROM   (
  SELECT department,
         InitialDate,
         FinalDate,
         SUM( grp_inc ) OVER ( ORDER BY FinalDate ) AS grp
  FROM   (
    SELECT department,
           InitialDate,
           FinalDate,
           CASE WHEN LAG( department ) OVER ( ORDER BY FinalDate ) = department 
                THEN 0
                ELSE 1
                END AS grp_inc
    FROM   table_name
  )
)
GROUP BY department, grp

答案 1 :(得分:0)

这是一种“差距和岛屿”问题。解决它的一种方法是确定重叠时间组的开始位置。然后使用累积和来定义每个组:

select departmentid, min(initialdate), max(finaldate)
from (select t.*, sum(grp_starts) over (partition by departmentid order by initialdate) as grp
      from (select t.*,
                   (case when exists (select 1
                                      from t t2
                                      where t2.departmentid = t.departmentid and
                                            t.initialdate > t2.initialdate and
                                            t.initialdate <= t2.finaldate 
                                     )
                         then 0 else 1
                     end) as grp_starts
            from t
           ) t
     ) t
group by departmentid, grp;

答案 2 :(得分:0)

由于您正在寻找部门更改的位置以及部门更改或初始日期与上一行的最后日期不同,您可以使用tabibitosan

WITH sample_data AS (SELECT 1 department, to_date('01/01/2017 01:12:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/03/2017 00:00:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 1 department, to_date('01/03/2017 00:00:08', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/04/2017 05:00:01', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 1 department, to_date('01/04/2017 05:00:01', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/05/2017 02:00:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 2 department, to_date('01/05/2017 10:00:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/06/2017 11:00:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 2 department, to_date('01/06/2017 11:00:08', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/07/2017 04:04:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 3 department, to_date('01/07/2017 04:00:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/07/2017 15:00:22', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 1 department, to_date('01/07/2017 14:00:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/07/2017 18:00:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 1 department, to_date('01/07/2017 18:15:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/08/2017 22:00:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 3 department, to_date('01/12/2017 01:30:03', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/12/2017 18:00:00', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual union all
                     SELECT 1 department, to_date('01/13/2017 23:12:00', 'mm/dd/yyyy hh24:mi:ss') initialdate, to_date('01/13/2017 23:59:08', 'mm/dd/yyyy hh24:mi:ss') finaldate from dual)
SELECT department,
       MIN(initialdate) initialdate,
       MAX(finaldate) finaldate
FROM   (SELECT department,
               initialdate,
               finaldate,
               row_number() OVER (ORDER BY initialdate)
                 - row_number() OVER (PARTITION BY department ORDER BY initialdate) grp
        FROM   sample_data sd)
GROUP BY department, grp
ORDER BY initialdate;

DEPARTMENT INITIALDATE         FINALDATE
---------- ------------------- -------------------
         1 01/01/2017 01:12:00 01/05/2017 02:00:00
         2 01/05/2017 10:00:00 01/07/2017 04:04:00
         3 01/07/2017 04:00:00 01/07/2017 15:00:22
         1 01/07/2017 14:00:00 01/08/2017 22:00:00
         3 01/12/2017 01:30:03 01/12/2017 18:00:00
         1 01/13/2017 23:12:00 01/13/2017 23:59:08

这可以通过遍历并编号按初始日期排序的所有行,并将它们与遍历和对每个部门的行进行编号进行比较。当部门改变时,数字之间的差异会发生变化。如果某个部门在初始数据集中有连续的行,则这些行的差异将保持不变。例如。在您的数据中,部门1有6行,前3行与初始数据集的前3行相同,因此这3行的差异为0.第4和第5部门1行是第7行和第8行数据集中的行,因此这些行的差异为3等。

这为我们提供了一个号码,我们可以将它与部门号一起用来对数据进行分组。然后,在该组中找到最小/最大日期就很简单了。