开始和结束日期范围的顺序分组

时间:2014-05-05 22:55:21

标签: sql sql-server sql-server-2005 grouping sequential

我有一个问题,我无法弄明白。我创建了一个视图,在运行时,它为我提供了旅行工作人员的位置数据。重要的部分是PlacementIDStartDateEndDate

TravelerID  FirstName   LastName    PlacementID StartDate   EndDate
--------------------------------------------------------------------
65648       Lori        Williams    106593      09/22/01    02/08/03
65648       Lori        Williams    392605      02/24/03    05/24/03
65648       Lori        Williams    477950      05/26/03    11/22/03
65648       Lori        Williams    600089      12/01/03    05/29/04
65648       Lori        Williams    717424      05/30/04    12/04/04
65648       Lori        Williams    832842      12/05/04    02/04/05
65648       Lori        Williams    867492      02/06/05    07/30/05
65648       Lori        Williams    979375      08/15/05    11/12/05
65648       Lori        Williams    1030555     11/14/05    05/13/06
65648       Lori        Williams    1155937     05/15/06    01/06/07
65648       Lori        Williams    1341007     01/07/07    01/05/08
65648       Lori        Williams    1709959     01/06/08    05/31/08
65648       Lori        Williams    1878735     06/01/08    07/19/08
65648       Lori        Williams    1937168     07/20/08    01/31/09

他们希望将连续展示位置计为一个,并使用第一个展示位置中的PlacementID。请注意PlacementID s 600089,717424和832842。请注意,下一个的开始日期是前一个结束日期之后的一天。列表中还有其他连续的展示位置。所以期望的输出是:

TravelerID  FirstName   LastName    PlacementID StartDate   EndDate
--------------------------------------------------------------------
65648       Lori        Williams    106593      09/22/01    02/08/03
65648       Lori        Williams    392605      02/24/03    05/24/03
65648       Lori        Williams    477950      05/26/03    11/22/03
65648       Lori        Williams    600089      12/01/03    02/04/05
65648       Lori        Williams    867492      02/06/05    07/30/05
65648       Lori        Williams    979375      08/15/05    11/12/05
65648       Lori        Williams    1030555     11/14/05    05/13/06
65648       Lori        Williams    1155937     05/15/06    01/31/09

以下是生成示例数据的一些代码:

CREATE TABLE [dbo].vw_PlacementData(
 TravelerID int
,FirstName varchar(255)
,LastName varchar(255)
,PlacementID int
,StartDate datetime
,EndDate datetime
) ON [PRIMARY]

INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',106593,'9/22/01','2/8/03')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',392605,'2/24/03','5/24/03')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',477950,'5/26/03','11/22/03')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',600089,'12/1/03','5/29/04')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',717424,'5/30/04','12/4/04')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',832842,'12/5/04','2/4/05')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',867492,'2/6/05','7/30/05')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',979375,'8/15/05','11/12/05')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',1030555,'11/14/05','5/13/06')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',1155937,'5/15/06','1/6/07')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',1341007,'1/7/07','1/5/08')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',1709959,'1/6/08','5/31/08')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',1878735,'6/1/08','7/19/08')
INSERT INTO vw_PlacementData VALUES (65648,'Lori','Williams',1937168,'7/20/08','1/31/09')

` 我试图将表格加入到自己的位置,但它没有考虑多个连续的展示位置。从示例中可以看出,可能需要计算2到20个连续的展示位置。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

有人在msdn论坛上提供了一个方便的解决方案。这是语法:

SELECT *
    ,CAST(NULL AS datetime) AS FinalStartDate
    ,CAST(NULL AS datetime) AS FinalEndDate 
INTO #temp
FROM vw_PlacementData

CREATE CLUSTERED INDEX IDX_Clust_temp ON #temp (TravelerID,PlacementID,StartDate,EndDate)

DECLARE 
     @TravelerID int
    ,@PlacementID int
    ,@StartDate datetime
    ,@EndDate datetime

SELECT TOP 1 
     @TravelerID =TravelerID 
    ,@PlacementID = PlacementID
    ,@StartDate  = StartDate
    ,@EndDate = EndDate
FROM vw_PlacementData
ORDER BY TravelerID,StartDate,EndDate

--SELECT TOP 1 @TravelerID,@PlacementID  ,@StartDate  ,@EndDate

UPDATE t
SET @StartDate = FinalStartDate = CASE 
                                    WHEN TravelerID = @TravelerID 
                                    AND PlacementID > @PlacementID 
                                    AND  StartDate = @EndDate + 1
                                  THEN @StartDate
                                  ELSE StartDate
                             END,
    @TravelerID =TravelerID
   ,@PlacementID = PlacementID 
 --,@StartDate  = FinalStartDate
   ,@EndDate = EndDate
 -- OUTPUT INSERTED.StartDate,INSERTED.EndDate
 FROM #temp t (TABLOCKX)
 OPTION (MAXDOP 1)

SELECT 
     TravelerID
    ,FirstName
    ,LastName
    ,MIN(PlacementID) AS PlacementID
    ,FinalStartDate AS StartDate
    ,MAX(EndDate) AS EndDate
FROM #temp
GROUP BY TravelerID,FirstName,LastName,FinalStartDate

DROP TABLE  #Temp

答案 1 :(得分:0)

您可以使用递归CTE根据开始/结束日期将展示位置片段加入到一起。

;WITH cteConsecutivePlacements AS(
    SELECT
         TravelerID
        ,FirstName
        ,LastName
        ,PlacementID
        ,StartDate
        ,EndDate
    FROM dbo.vw_PlacementData

    UNION ALL

    SELECT
         cte.TravelerID
        ,cte.FirstName
        ,cte.LastName
        ,cte.PlacementID
        ,cte.StartDate
        ,vpd.EndDate
    FROM cteConsecutivePlacements cte
    JOIN dbo.vw_PlacementData vpd
        ON cte.TravelerID = vpd.TravelerID
    WHERE DATEADD(DAY,1,cte.EndDate) = vpd.StartDate
)

内部select语句使用ROW_NUMBER函数来标识后续的展示位置,外部select语句中的聚合将结果减少到每个连续展示位置1行,并使用正确的结束日期。

SELECT
     TravelerID
    ,FirstName
    ,LastName
    ,PlacementID
    ,StartDate
    ,MAX(EndDate) AS EndDate
FROM( 
    SELECT 
         TravelerID
        ,FirstName
        ,LastName
        ,PlacementID
        ,StartDate
        ,EndDate
        ,ROW_NUMBER() OVER(PARTITION BY TravelerID, FirstName, LastName, EndDate ORDER BY StartDate ASC) AS row_num
    FROM cteConsecutivePlacements   
)q
WHERE q.row_num = 1
GROUP BY TravelerID, FirstName, LastName, PlacementID, StartDate
ORDER BY PlacementID, EndDate