结合2个表的日期间隔

时间:2015-07-07 18:33:54

标签: 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  | 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')
 

1 个答案:

答案 0 :(得分:0)

这样的事情可能是你所需要的吗?

我的方法是,给句点一个键,并使用句点或year_month作为分区avg-function的关键(OVER子句:https://msdn.microsoft.com/en-us/library/ms189461.aspx

编辑:新方法,因为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