2013-07-10 93 views
2

我想從項目列表中生成一個項目,日期範圍摘要,sql-2008的日期。tsql到日期範圍的日期列表

DECLARE @RoomDays AS TABLE (
    [RoomID] [int] NOT NULL, 
    [DateOf] [date] NOT NULL, 
    [Segment] [char](1) NOT NULL 
) 

INSERT INTO @RoomDays 
VALUES 
('1','2013-07-03','1'), 
('1','2013-07-04','1'), 
('1','2013-07-05','6'), 
('1','2013-07-15','6'), 
('1','2013-07-16','6'), 
('2','2013-07-08','1'), 
('2','2013-07-09','1'), 
('2','2013-07-10','6'), 
('2','2013-07-11','6'), 
('2','2013-07-12','1'), 
('2','2013-07-13','1'), 
('3','2013-07-19','6') 

結果我想獲得:

RoomID DateFrom DateThru Segments  NumDays 
1  2013-07-03 2013-07-05 1,1,6  3 
1  2013-07-15 2013-07-16 6,6   2 
2  2013-07-08 2013-07-13 1,1,6,6,1,1 6 
3  2013-07-19 2013-07-19 6   1 

我只是不能讓我圍繞如何做到這一點的頭......

..maybe本作的段列:

( 
SELECT CAST(ltrim(rtrim(SegmentID)) + ', ' AS VARCHAR(MAX)) 
from @RoomDays where roomid = rd.roomid 
FOR XML PATH ('') 
)+' ' as Segments, 
-- 

任何幫助或指導,將不勝感激。

+0

嘗試找到關於「差距和島嶼」的信息。 – GilM

+0

如何區分結果中的第一行和第二行,因爲id是一樣的? – Tomasito

+0

我在5月發表了關於這個東西的博文。這篇文章在瑞典這裏:http://blogs.solidq.com/SQL-Server-pa-svenska/Post.aspx?ID=24&title=Hur+konkatenering+med+FOR+XML+PATH+fungerar。我通過谷歌翻譯來運行它,事實證明,ok-ish(警告詞,英文和瑞典語中的重疊詞可能已經在代碼中進行了翻譯)。看看這裏:http://translate.google.com/translate?sl=sv&tl=en&js=n&prev=_t&hl=zh-CN&ie=UTF-8&u=http%3A%2F%2Fblogs.solidq.com%2FSQL-Server-pa -svenska%2FPost.aspx%3FID%3D24%26title%3DHur%2Bkonkatenering%2Bmed%2BFOR%2BXML%2BPATH%2Bfungerar。 –

回答

0

獲取日期範圍是古老的差距和島嶼問題。 使用您所描述的XML技巧來連接您的細分。

下面是一個SQL搗鼓一個完整的解決方案:http://sqlfiddle.com/#!3/d4a961/11

使用你的代碼中的問題和表變量的代碼應該是這樣的:

WITH groupedDays AS (
SELECT 
RoomID 
,DateOf 
,Segment 
,DATEADD(day,-row_number() OVER (partition by RoomID order by DateOf),DateOf) AS Island 
FROM @RoomDays 
) 

SELECT 
outerTable.RoomID 
,MIN(outerTable.DateOf) AS DateFrom 
,MAX(outerTable.DateOf) AS DateThru 
,STUFF((
    SELECT ', ' + innerTable.Segment 
    FROM groupedDays AS innerTable 
    WHERE innerTable.RoomID = outerTable.RoomID 
    AND innerTable.Island = outerTable.Island 
    ORDER BY innerTable.DateOf 
    FOR XML PATH('') 
),1,1,'') 
,COUNT(*) AS NumDays 

FROM groupedDays AS outerTable 

GROUP BY 
outerTable.RoomID 
,outerTable.Island 

ORDER BY 
outerTable.RoomID 
,outerTable.Island 
0

下面的代碼是完全工作示例與你的樣本數據,這裏是一些有用的鏈接:

T-SQL CSV from column values

Recursive CTE

SET NOCOUNT ON 
GO 

    DECLARE @RoomDays TABLE 
    (
     [RoomID] INT NOT NULL 
     ,[DateOf] DATE NOT NULL 
     ,[Segment] CHAR(1) NOT NULL 
    ) 

    INSERT INTO @RoomDays ([RoomID], [DateOf], [Segment]) 
    VALUES ('1','2013-07-03','1') 
      ,('1','2013-07-04','1') 
      ,('1','2013-07-05','6') 
      ,('1','2013-07-15','6') 
      ,('1','2013-07-16','6') 
      ,('2','2013-07-08','1') 
      ,('2','2013-07-09','1') 
      ,('2','2013-07-10','6') 
      ,('2','2013-07-11','6') 
      ,('2','2013-07-12','1') 
      ,('2','2013-07-13','1') 
      ,('3','2013-07-19','6') 

    ;WITH DataSource ([RoomID], [DateOf], [Segment], [Level]) AS 
    (
     SELECT [RoomID], [DateOf], [Segment], 0 AS [Level] 
     FROM @RoomDays AS RD 
     UNION ALL 
     SELECT RD1.[RoomID], RD1.[DateOf], RD1.[Segment], [Level] + 1 
     FROM @RoomDays AS RD1 
     INNER JOIN DataSource DS 
      ON RD1.RoomID = DS.RoomID 
     WHERE DATEADD (DAY , 1 , DS.DateOf) = RD1.DateOf 
    ), 
    StartDates AS 
    (
     -- Retriving the "Start" records 
     SELECT [RoomID], [DateOf], [Segment] 
     FROM DataSource 
     WHERE [Level] = 0 
     EXCEPT 
     SELECT [RoomID], [DateOf], [Segment] 
     FROM DataSource 
     WHERE [Level] = 1 
    ), 
    TempResult AS 
    (
     -- Mathing each "Start" record with its values 
     SELECT SD.[DateOf] AS [StartDate] 
       ,RD.[RoomId] 
       ,RD.[DateOf] 
       ,RD.[Segment] 
     FROM StartDates SD 
     INNER JOIN @RoomDays RD 
      ON SD.RoomID = RD.RoomID 
      AND SD.DateOf <= RD.DateOf  
      AND NOT EXISTS (SELECT 1 FROM StartDates WHERE DateOf <= RD.DateOf AND RoomID = RD.RoomID AND SD.DateOf < DateOf) 
    ) 
    SELECT TR.[RoomID] AS [RoomID] 
      ,MIN(TR.[DateOf]) AS [DateFrom] 
      ,MAX(TR.[DateOf]) AS [DateThru] 
      ,SUBSTRING((SELECT ',' + [Segment] FROM TempResult WHERE [StartDate] = TR.[StartDate] FOR XML PATH('')),2,4000) AS CSV 
      ,COUNT(TR.[DateOf]) AS [NumDays] 
    FROM TempResult TR 
    GROUP BY TR.[RoomID],TR.[StartDate] 

SET NOCOUNT OFF 
GO 

OUTPUT:

1 2013-07-03 2013-07-05 1,1,6 3 
1 2013-07-15 2013-07-16 6,6 2 
2 2013-07-08 2013-07-13 1,1,6,6,1,1 6 
3 2013-07-19 2013-07-19 6 1 

請注意,上面的代碼可以被放入視圖或函數,或者您也可以「砍」它,並從每個CTE結果保存在臨時或表變量表。