我正在尝试从项目列表生成项目,日期范围摘要,sql-2008的日期。
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
我无法理解如何做到这一点......
..也许这是Segments专栏:
(
SELECT CAST( ltrim(rtrim(SegmentID)) + ', ' AS VARCHAR(MAX))
from @RoomDays where roomid = rd.roomid
FOR XML PATH ('')
)+' ' as Segments,
--
任何帮助或指导都将不胜感激。
答案 0 :(得分:0)
获取日期范围是古老的Gaps and Islands问题。 使用您描述的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
答案 1 :(得分:0)
以下代码是您的示例数据的完整工作示例,以下是一些有用的链接:
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
输出:
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的结果保存在临时或表变量表中。