2015-09-02 88 views
3

我有表具有以下的列:分組通過連續的日期在SQL Server

[name_of_pos] varchar, 
[date_from] datetime, 
[date_to] datetime 

下面是我的樣本數據:

name_of_pos date_from     date_to 
---------------------------------------------------------------- 
Asystent  2015-08-26 08:57:49.000 2015-09-04 08:57:49.000 
Biuro  2015-09-01 08:53:32.000 2015-09-01 08:53:32.000 
Biuro  2015-09-02 09:00:41.000 2015-09-02 09:00:41.000 
Biuro  2015-09-03 11:46:03.000 2015-09-03 11:46:03.000 
Biuro  2015-09-10 09:02:11.000 2015-09-15 09:02:11.000 
Koordynator 2015-09-01 09:04:06.000 2015-09-01 09:04:06.000 
Projektant 2015-08-31 08:59:46.000 2015-09-01 08:59:46.000 
Projektant 2015-09-02 08:00:54.000 2015-09-02 08:00:54.000 
Projektant 2015-09-14 12:34:50.000 2015-09-14 12:34:50.000 

我想要回是日期範圍(分date_from到最大date_to),但每個name_of_pos只有日期值是連續的(時間部分不重要,結果可以忽略)。

所需的輸出將是:

name_of_pos date_from date_to 
    ------------------------------------ 
    Asystent  2015-08-26 2015-09-04 
    Biuro   2015-09-01 2015-09-03 
    Biuro   2015-09-10 2015-09-15 
    Koordynator 2015-09-01 2015-09-01 
    Projektant 2015-08-31 2015-09-02 
    Projektant 2015-09-14 2015-09-14 

我用類似這樣的問題的東西嘗試瞭解決方案:

How do I group on continuous ranges

但沒有運氣,因爲我有兩個datetime列。

+0

您確定您提供的源數據是正確的嗎?如果是這樣,你能解釋一下你是如何獲得'Biuro 2015-09-01 08:53:32。2015-09-03 11:46:3。此記錄的源數據中似乎沒有連續的時間間隔。 – GolfWolf

+0

日期部分必須是連續的,時間部分不重要(可以忽略),所以biuro的三條記錄(其中date_from爲2015-09-01,2015-09-02和2015-09-03)應該返回爲一個row for name_of_pos ='Biuro'with values date_from ='2015-09-01'and date_to ='2015-09-03' – Bart

回答

1

下面是一個使用cte遍歷行(他們已經下令後),並檢查了連續幾天的解決方案分組之前:

-- dummy table 
CREATE TABLE #TableA 
    (
     [name_of_pos] VARCHAR(11) , 
     [date_from] DATETIME , 
     [date_to] DATETIME 
    ); 

-- insert dummy data 
INSERT INTO #TableA 
     ([name_of_pos], [date_from], [date_to]) 
VALUES ('Asystent', '2015-08-26 08:57:49', '2015-09-04 08:57:49'), 
     ('Biuro', '2015-09-01 08:53:32', '2015-09-01 08:53:32'), 
     ('Biuro', '2015-09-02 09:00:41', '2015-09-02 09:00:41'), 
     ('Biuro', '2015-09-03 11:46:03', '2015-09-03 11:46:03'), 
     ('Biuro', '2015-09-10 09:02:11', '2015-09-15 09:02:11'), 
     ('Koordynator', '2015-09-01 09:04:06', '2015-09-01 09:04:06'), 
     ('Projektant', '2015-08-31 08:59:46', '2015-09-01 08:59:46'), 
     ('Projektant', '2015-09-02 08:00:54', '2015-09-02 08:00:54'), 
     ('Projektant', '2015-09-14 12:34:50', '2015-09-14 12:34:50'); 

-- new temp table used to add row numbers for data order 
SELECT name_of_pos, CAST(date_from AS DATE) date_from, CAST(date_to AS DATE) date_to, 
     ROW_NUMBER() OVER (ORDER BY name_of_pos, date_from) rn 
INTO #temp 
FROM #TableA 

-- GroupingColumn in cte used to identify and group consecutive dates 
;WITH cte 
      AS (SELECT name_of_pos , 
         date_from , 
         date_to , 
         1 AS GroupingColumn , 
         rn 
       FROM  #temp 
       WHERE rn = 1 
       UNION ALL 
       SELECT t2.name_of_pos , 
         t2.date_from , 
         t2.date_to , 
         CASE WHEN t2.date_from = DATEADD(day, 1, cte.date_to) 
            AND cte.name_of_pos = t2.name_of_pos 
          THEN cte.GroupingColumn 
          ELSE cte.GroupingColumn + 1 
         END AS GroupingColumn , 
         t2.rn 
       FROM  #temp t2 
         INNER JOIN cte ON t2.rn = cte.rn + 1 
      ) 
    SELECT name_of_pos, MIN(date_from) AS date_from, MAX(date_to) AS date_to 
    FROM cte 
    GROUP BY name_of_pos, GroupingColumn 

DROP TABLE #temp 
DROP TABLE #TableA 

將製作所需輸出:

name_of_pos date_from date_to 
Asystent 2015-08-26 2015-09-04 
Biuro  2015-09-01 2015-09-03 
Biuro  2015-09-10 2015-09-15 
Koordynator 2015-09-01 2015-09-01 
Projektant 2015-08-31 2015-09-02 
Projektant 2015-09-14 2015-09-14 
+0

工程很棒,謝謝你!我還有一個問題 - 可以用這個查詢創建視圖嗎? – Bart

+0

@Bart是的,你應該可以做到[像這樣](http://dba.stackexchange。COM /問題/ 7239 /與Transact-SQL使用 - :在創建視圖) – Tanner

+0

你比你的結構,你必須投日期時間至今偉大工程,再次非常非常感謝 – Bart

-2

嘗試這一次,

SELECT name_of_pos, date_from,date_to 
FROM table 
ORDER BY 
name_of_pos asc, date_from desc; 
+1

您錯過了分組部分.. – jarlh

+0

它爲Biuro返回四條記錄,而不是2015年的兩條記錄-09-01到2015-09-03第二個2015-09-10到2015-09-15 – Bart

+0

是的,上面不會幫你。想着另一個查詢 –

0

您可以使用cte爲,但是從我的經驗,這樣做的最快方法是在一個循環中使用更新:

declare @temp table 
(
    name_of_pos varchar(128), 
    date_from datetime, 
    date_to datetime 
) 

insert into @temp (
    name_of_pos, date_from, date_to 
) 
values 
    ('Asystent', '2015-08-26 08:57:49', '2015-09-04 08:57:49'), 
    ('Biuro', '2015-09-01 08:53:32', '2015-09-01 08:53:32'), 
    ('Biuro', '2015-09-02 09:00:41', '2015-09-02 09:00:41'), 
    ('Biuro', '2015-09-03 11:46:03', '2015-09-03 11:46:03'), 
    ('Biuro', '2015-09-10 09:02:11', '2015-09-15 09:02:11'), 
    ('Koordynator', '2015-09-01 09:04:06', '2015-09-01 09:04:06'), 
    ('Projektant', '2015-08-31 08:59:46', '2015-09-01 08:59:46'), 
    ('Projektant', '2015-09-02 08:00:54', '2015-09-02 08:00:54'), 
    ('Projektant', '2015-09-14 12:34:50', '2015-09-14 12:34:50') 

---------------------------------------------------------------------------------------------------- 
declare @temp_new table (
    name_of_pos varchar(128), 
    date_from date, 
    date_to date 
) 

insert into @temp_new (
    name_of_pos, date_from, date_to 
) 
select 
    name_of_pos, date_from, date_to 
from @temp 

while @@rowcount > 0 
begin 
    update t1 set 
     date_to = t2.date_to 
    from @temp_new as t1 
     inner join @temp_new as t2 on 
      t2.name_of_pos = t1.name_of_pos and 
      dateadd(dd, 1, t1.date_to) = t2.date_from 
end 

select name_of_pos, min(date_from), date_to 
from @temp_new 
group by name_of_pos, date_to 
order by name_of_pos, date_to 
0

這是一個差距和島嶼問題。這是爲了完成它的調諧official方式,這將被檢查作爲溶液:

;with 

cte as (
    SELECT *, 
      dateadd(day, 
      - (ROW_NUMBER() OVER (
       partition by name_of_pos 
       ORDER BY t.date_from 
      ) +       -- here starts tuned part -- 
       isnull( 
       sum(datediff(day, date_from, date_to)) OVER (
       partition by name_of_pos 
       ORDER BY t.date_from 
       ROWS BETWEEN UNBOUNDED PRECEDING and 1 PRECEDING 
      ) ,0)       -- here ends tuned part -- 
      ), 
      date_from 
     ) as Grp 
    FROM t 
) 

SELECT name_of_pos 
    ,min(date_from) AS date_from 
    ,max(date_to) AS date_to 
FROM cte 
GROUP BY name_of_pos, Grp 
ORDER BY name_of_pos, date_from 

tested on sqlfiddle這裏(有一些幾個不同的樣本數據)。

+0

(通知) – danihp

+0

唯一的缺點它不能適用於重疊期間,但在連續期間的情況下,這應該是相當不錯的。 我將行的大量檢查並「會回來 –

+0

也是你可能想提一提,這將在SQL Server 2012+ –