Sql server 合并两个表中的日期间隔

Sql server 合并两个表中的日期间隔,sql-server,date,Sql Server,Date,我每天在一张桌子上测量储藏室的温度,每个房间有一张单独的桌子: begindate | enddate | temperature | room_id -------------------------------------------- 1/1/2014 | 1/2/2014 | 10 | 1 1/2/2014 | 1/3/2014 | 12 | 1 1/4/2014 | 1/5/2014 | 11 | 1 1/5/2014

我每天在一张桌子上测量储藏室的温度,每个房间有一张单独的桌子:

begindate | enddate | temperature | room_id -------------------------------------------- 1/1/2014 | 1/2/2014 | 10 | 1 1/2/2014 | 1/3/2014 | 12 | 1 1/4/2014 | 1/5/2014 | 11 | 1 1/5/2014 | 1/6/2014 | 12 | 1 1/6/2014 | 1/7/2014 | 10 | 1 1/7/2014 | 1/8/2014 | 11 | 1 1/8/2014 | 1/9/2014 | 12 | 1 ...... 1/29/2014 | 1/30/2014| 10 | 1 1/30/2014 | 1/31/2014| 12 | 1 1/31/2014 | 2/1/2014 | 10 | 1 ...... 3/1/2014 | 3/2/2014 | 14 | 1 ..... Does not show all dates but the measurements are daily 第二个表包含存储室被占用的日期

begindate | enddate | room_id --------------------------------- 1/6/2014 | 1/9/2014 | 1 1/15/2014 | 1/29/2014 | 1 3/1/2014 | 3/2/2014 | 1 我需要的是房间被占用期间的平均室温,或者如果房间未被占用或占用时间超过一个月,则需要每月的温度。 根据上述数据,结果应如下所示:

begindate | enddate | avg_temp | room_id -------------------------------------------------- 1/1/2014 | 1/6/2014 | 11 | 1 1/6/2014 | 1/9/2014 | 11 | 1 1/9/2014 | 1/15/2014 | 11 | 1 1/15/2014 | 1/29/2014 | 12 | 1 1/29/2014 | 2/1/2014 | 11 | 1 2/1/2014 | 3/1/2014 | 13 | 1 3/1/2014 | 3/2/2014 | 14 | 1 3/2/2014 | 4/1/2014 | 15 | 1 我尝试了几种方法,但每次都会出现重复的重叠日期或丢失的日期间隔。 任何帮助都将不胜感激

代码创建温度数据表: INSERT INTO @temps values ('01/01/2014','01/02/2014','10','1'), ('01/02/2014','01/03/2014','12','1'), ('01/03/2014','01/04/2014','11','1'), ('01/04/2014','01/05/2014','11','1'), ('01/05/2014','01/06/2014','12','1'), ('01/06/2014','01/07/2014','10','1'), ('01/07/2014','01/08/2014','11','1'), ('01/08/2014','01/09/2014','12','1'), ('01/09/2014','01/10/2014','10','1'), ('01/10/2014','01/11/2014','12','1'), ('01/11/2014','01/12/2014','10','1'), ('01/12/2014','01/13/2014','10','1'), ('01/13/2014','01/14/2014','11','1'), ('01/14/2014','01/15/2014','12','1'), ('01/15/2014','01/16/2014','11','1'), ('01/16/2014','01/17/2014','14','1'), ('01/17/2014','01/18/2014','12','1'), ('01/18/2014','01/19/2014','10','1'), ('01/19/2014','01/20/2014','11','1'), ('01/20/2014','01/21/2014','10','1'), ('01/21/2014','01/22/2014','11','1'), ('01/22/2014','01/23/2014','12','1'), ('01/23/2014','01/24/2014','11','1'), ('01/24/2014','01/25/2014','14','1'), ('01/25/2014','01/26/2014','12','1'), ('01/26/2014','01/27/2014','10','1'), ('01/27/2014','01/28/2014','11','1'), ('01/28/2014','01/29/2014','10','1'), ('01/29/2014','01/30/2014','11','1'), ('01/30/2014','01/31/2014','12','1'), ('01/31/2014','02/01/2014','11','1'), ('02/01/2014','02/02/2014','14','1'), ('02/02/2014','02/03/2014','12','1'), ('02/03/2014','02/04/2014','10','1'), ('02/04/2014','02/05/2014','11','1'), ('02/05/2014','02/06/2014','10','1'), ('02/06/2014','02/07/2014','11','1'), ('02/07/2014','02/08/2014','12','1'), ('02/08/2014','02/09/2014','11','1'), ('02/09/2014','02/10/2014','14','1'), ('02/10/2014','02/11/2014','12','1'), ('02/11/2014','02/12/2014','10','1'), ('02/12/2014','02/13/2014','11','1'), ('02/13/2014','02/14/2014','10','1'), ('02/14/2014','02/15/2014','11','1'), ('02/15/2014','02/16/2014','12','1'), ('02/16/2014','02/17/2014','11','1'), ('02/17/2014','02/18/2014','14','1'), ('02/18/2014','02/19/2014','12','1'), ('02/19/2014','02/20/2014','10','1'), ('02/20/2014','02/21/2014','11','1'), ('02/21/2014','02/22/2014','10','1'), ('02/22/2014','02/23/2014','11','1'), ('02/23/2014','02/24/2014','12','1'), ('02/24/2014','02/25/2014','11','1'), ('02/25/2014','02/26/2014','14','1'), ('02/26/2014','02/27/2014','12','1'), ('02/27/2014','02/28/2014','15','1'), ('02/28/2014','03/01/2014','11','1'), ('03/01/2014','03/02/2014','11','1'), ('03/02/2014','03/03/2014','12','1'), ('03/03/2014','03/04/2014','11','1'), ('03/04/2014','03/05/2014','14','1'), ('03/05/2014','03/06/2014','12','1'), ('03/06/2014','03/07/2014','15','1'), ('03/07/2014','03/08/2014','11','1'), ('03/08/2014','03/09/2014','12','1'), ('03/09/2014','03/10/2014','11','1'), ('03/10/2014','03/11/2014','14','1'), ('03/11/2014','03/12/2014','12','1'), ('03/12/2014','03/13/2014','15','1'), ('03/13/2014','03/14/2014','11','1'), ('03/14/2014','03/15/2014','12','1'), ('03/15/2014','03/16/2014','11','1'), ('03/16/2014','03/17/2014','14','1'), ('03/17/2014','03/18/2014','12','1'), ('03/18/2014','03/19/2014','15','1'), ('03/19/2014','03/20/2014','11','1'), ('03/20/2014','03/21/2014','12','1'), ('03/21/2014','03/22/2014','11','1'), ('03/22/2014','03/23/2014','14','1'), ('03/23/2014','03/24/2014','12','1'), ('03/24/2014','03/25/2014','15','1'), ('03/25/2014','03/26/2014','11','1'), ('03/26/2014','03/27/2014','12','1'), ('03/27/2014','03/28/2014','11','1'), ('03/28/2014','03/29/2014','14','1'), ('03/29/2014','03/30/2014','12','1'), ('03/30/2014','03/31/2014','15','1'), ('03/31/2014','04/01/2014','11','1'), ('04/01/2014','04/02/2014','12','1'), ('04/02/2014','04/03/2014','11','1'), ('04/03/2014','04/04/2014','14','1'), ('04/04/2014','04/05/2014','12','1'), ('04/05/2014','04/06/2014','15','1')
像这样的东西能满足你的需要吗

我的方法是,给周期一个键,并使用周期或年\月作为键来划分avg函数OVER子句:

编辑:新方法,因为OP需要其他东西:

备注:如果自由期必须在真实期开始时结束,并且在真实期结束后必须有一个新的自由期,我可以建议另一种方法,但这在一个答案中太多了。请让我知道

编辑:我的话正是重点,所以我建议另一种方法:

SET LANGUAGE English;

DECLARE @rooms TABLE(roomID INT,room VARCHAR(10));
INSERT INTO @rooms VALUES(1,'Room 1'),(2,'Room 2');

DECLARE @temps TABLE(begD DATE, endD DATE,temp INT, roomID INT);
INSERT INTO @temps 
VALUES('1/1/2014','1/2/2014','10','1')
     ,('1/2/2014','1/3/2014','12','1')
     ,('1/4/2014','1/5/2014','11','1')
     ,('1/5/2014','1/6/2014','12','1')
     ,('1/6/2014','1/7/2014','10','1')
     ,('1/7/2014','1/8/2014','11','1')
     ,('1/8/2014','1/9/2014','12','1')
     ,('1/29/2014','1/30/2014','10','1')
     ,('1/30/2014','1/31/2014','12','1')
     ,('1/31/2014','2/1/2014','10','1')
     ,('3/1/2014','3/2/2014','14','1');

DECLARE @periods TABLE(periodID INT, begD DATE,endD DATE,roomID INT);
INSERT INTO @periods
VALUES(1,'1/6/2014','1/9/2014','1')
     ,(2,'1/15/2014','1/29/2014','1')
     ,(3,'3/1/2014','3/2/2014','1');

DECLARE @StartDate DATE='1/1/2014';
DECLARE @DayCount INT=50;
WITH dayList AS
(
    SELECT TOP (@DayCount) DATEADD(d,numbers.nr-1,@StartDate) AS dayDate
    FROM
    (
        SELECT ROW_NUMBER() OVER(ORDER BY o.object_id) FROM sys.objects AS o
    ) AS numbers(nr)
)
,roomDayList AS
(
    SELECT dayList.dayDate,r.* 
    FROM dayList,@rooms AS r

)
,occupations AS
(
    SELECT roomDayList.dayDate
          ,roomDayList.roomID
          ,roomDayList.room
          ,ISNULL(InPeriod.PeriodID,'free') AS PeriodID
    FROM roomDayList
    OUTER APPLY
    (
        SELECT 'P'+CAST(periodID AS VARCHAR(MAX)) AS PeriodID
        FROM @periods AS p
        WHERE p.roomID=roomDayList.roomID
          AND roomDayList.dayDate BETWEEN p.begD AND p.endD   
    ) InPeriod
)
,periodBorders AS
(
    SELECT tbl.*
    FROM
    (
        SELECT occupations.*
              ,CASE WHEN occupations.dayDate=@StartDate THEN @StartDate ELSE CASE WHEN occupations.PeriodID<>RowBefore.PeriodID THEN occupations.dayDate ELSE NULL END END AS FirstDayOfPeriod
              ,CASE WHEN occupations.dayDate=(SELECT MAX(dayDate) FROM dayList) THEN (SELECT MAX(dayDate) FROM dayList) ELSE CASE WHEN occupations.PeriodID<>RowAfter.PeriodID THEN occupations.dayDate ELSE NULL END END AS LastDayOfPeriod
        FROM occupations
        OUTER APPLY
        (
            SELECT PeriodID
            FROM occupations AS innerOc
            WHERE innerOc.dayDate=DATEADD(d,-1,occupations.dayDate)
              AND innerOc.roomID=occupations.roomID
        ) AS RowBefore
        OUTER APPLY
        (
            SELECT PeriodID
            FROM occupations AS innerOc
            WHERE innerOc.dayDate=DATEADD(d,1,occupations.dayDate)
              AND innerOc.roomID=occupations.roomID
        ) AS RowAfter
    ) AS tbl
    WHERE tbl.FirstDayOfPeriod IS NOT NULL OR tbl.LastDayOfPeriod IS NOT NULL
)
,mergeBorders AS
(
    SELECT periodBorders.dayDate
          ,periodBorders.roomID
          ,periodBorders.room
          ,periodBorders.PeriodID
          ,periodBorders.FirstDayOfPeriod
          ,ISNULL(periodBorders.LastDayOfPeriod,PeriodEndDate.dt) AS LastDayOfPeriod
    FROM periodBorders
    CROSS APPLY
    (
        SELECT TOP 1 pB.LastDayOfPeriod FROM periodBorders AS pB WHERE pB.roomID=periodBorders.roomID AND pB.dayDate>periodBorders.dayDate ORDER BY pB.dayDate ASC
    ) AS PeriodEndDate(dt)
    WHERE periodBorders.FirstDayOfPeriod IS NOT NULL
)
,tempMeasures AS
(
    SELECT t.temp
          ,Period.*
    FROM @temps AS t
    CROSS APPLY
    (
        SELECT * 
        FROM mergeBorders
        WHERE mergeBorders.roomID=t.roomID AND t.begD BETWEEN mergeBorders.FirstDayOfPeriod AND mergeBorders.LastDayOfPeriod
    ) AS Period
)
SELECT t.roomID
      ,t.FirstDayOfPeriod
      ,t.LastDayOfPeriod
      ,AVG(t.temp)
FROM tempMeasures AS t
GROUP BY t.FirstDayOfPeriod,t.LastDayOfPeriod,t.roomID
ORDER BY t.roomID,t.FirstDayOfPeriod

请发布您解决此问题的尝试,以便我们可以帮助您找出问题所在。谢谢,我可以开始处理他的问题,但是我只需要每个periodID有一条记录,其中包含时段的开始和结束日期。还有一个建议:我将编辑我的答案,如果这对你有帮助的话,请在那里查阅,不要忘记向上投票:-好吧,我想当你分组时问题就开始了:我们现在有重叠的间隔。例如,日期间隔为2014年1月1日至2014年1月31日,涵盖了其他两个时间间隔——2014年6月1日至2014年9月1日和2014年1月15日至2014年1月29日。我们应该将这三个时间间隔改为2014年1月1日至2014年1月6日、2014年1月6日至2014年1月9日、2014年1月9日至2014年1月15日、2014年1月15日至2014年1月29日和2014年1月29日至2014年2月1日。这是一个相当大的挑战,我无法停止:-我的解决方案在答案中编辑。希望这是你需要的。。。如果是,请标记答案,谢谢!抱歉,花了很长时间来验证整个过程是否正常。但确实如此。谢谢!