2013-02-19 98 views
0

我正在嘗試查找處理日期中給定值的下列數據的最小值和最大值處理日期(請注意,行不會在週末處理,我不想將它們分解成兩組不同的,如果他們有相同的值)SQL - 獲取給定組的最小最大日期,並且有中斷日期

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

+0

對不起,我不明白你的理由分裂日期,因爲你有。你能解釋一下嗎?我相信你正在看[標籤:間隙和島嶼]問題,但我不能確定。 – Ben 2013-02-19 17:52:04

+0

@ben,如果您看到數據代碼有10個值,從01/10到01/11以及01/17到01/18有效,從01/12到01/16有9個值。我想返回值的最大值和最小值日期,並根據這些日期更新其他表中的值。現在從我原來的查詢它有兩個值9,10日期範圍01/12至01/16這是不正確的。 – rstech 2013-02-19 18:02:30

+0

@ 2012年1月14日,14日和15日是週末 – rstech 2013-02-19 18:22:43

回答

0

不知道你想要什麼?你沒有正確的數據按日期進行分區。你的日期是獨一無二的,除非你的意思是你的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 
0

這是網站上尋求解決同樣問題的其他一些問題。例子是herehere,這些只是我提供答案的問題。

這個問題有點複雜,因爲忽略週末的要求。這個問題似乎相對比較簡單,我將很快解釋。

您的問題不包括表格中所有列的列名稱。我假設第一個日期是過程日期,另一個日期對於此查詢並不重要。這可能是錯誤的假設。

從這個問題來看,如果在一個工作日(週一到週四)的第二天有一個匹配的行,它看起來像一個組。對於星期五,下週一需要有匹配的行。我處理這個問題的方法是,如果是星期五,或者在其他情況下每天增加一天,則增加3天。

示例查詢如下所示,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