SQL Server如何将5分钟的间隔重新组合为15分钟中的1分钟?

时间:2016-12-19 13:29:05

标签: sql-server group-by common-table-expression appointment

我正在建立一个网站,您可以在线获取任命。我不会详细解释所有内容,但我有一张桌子,上面有我可以预约的时间。分布到5分钟的间隔。这是一个例子:

ID      StartDate               EndDate
492548  2016-12-16 08:00:00.000 2016-12-16 08:05:00.000
492549  2016-12-16 08:05:00.000 2016-12-16 08:10:00.000
492550  2016-12-16 08:10:00.000 2016-12-16 08:15:00.000
492551  2016-12-16 08:15:00.000 2016-12-16 08:20:00.000
492552  2016-12-16 08:20:00.000 2016-12-16 08:25:00.000
492553  2016-12-16 08:25:00.000 2016-12-16 08:30:00.000
492554  2016-12-16 08:30:00.000 2016-12-16 08:35:00.000
492555  2016-12-16 08:35:00.000 2016-12-16 08:40:00.000
492556  2016-12-16 08:40:00.000 2016-12-16 08:45:00.000
492557  2016-12-16 08:45:00.000 2016-12-16 08:50:00.000
492558  2016-12-16 08:50:00.000 2016-12-16 08:55:00.000
492559  2016-12-16 08:55:00.000 2016-12-16 09:00:00.000
492560  2016-12-16 09:00:00.000 2016-12-16 09:05:00.000
492561  2016-12-16 09:05:00.000 2016-12-16 09:10:00.000
492562  2016-12-16 09:10:00.000 2016-12-16 09:15:00.000
492563  2016-12-16 09:15:00.000 2016-12-16 09:20:00.000
492564  2016-12-16 09:20:00.000 2016-12-16 09:25:00.000
492565  2016-12-16 09:25:00.000 2016-12-16 09:30:00.000
492566  2016-12-16 09:30:00.000 2016-12-16 09:35:00.000

根据咨询时间,根据咨询的原因,我必须将这些行分组为一个并知道min(IDSchedulingInterval)和max(IDSchedulingInterval)。

如果我的持续时间为15分钟,这是我想要的结果示例:

Min(ID) Max(ID) StartDate               EndDate
492548  492550  2016-12-16 08:00:00.000 2016-12-16 08:15:00.000
492551  492553  2016-12-16 08:15:00.000 2016-12-16 08:30:00.000
492554  492556  2016-12-16 08:30:00.000 2016-12-16 08:45:00.000
492557  492559  2016-12-16 08:45:00.000 2016-12-16 09:00:00.000

持续时间可以改变。我不知道如何继续进行此查询..

修改 以下是您必须检查的一些例外情况。这是我的表

ID      StartDate               EndDate                  Isreserved
492548  2016-12-16 08:00:00.000 2016-12-16 08:05:00.000  0  
492549  2016-12-16 08:05:00.000 2016-12-16 08:10:00.000  0  
492550  2016-12-16 08:10:00.000 2016-12-16 08:15:00.000  0  
492551  2016-12-16 08:15:00.000 2016-12-16 08:20:00.000  0  
492552  2016-12-16 08:20:00.000 2016-12-16 08:25:00.000  0      
492555  2016-12-16 08:35:00.000 2016-12-16 08:40:00.000  0  
492556  2016-12-16 08:40:00.000 2016-12-16 08:45:00.000  0  
492557  2016-12-16 08:45:00.000 2016-12-16 08:50:00.000  1  
492558  2016-12-16 08:50:00.000 2016-12-16 08:55:00.000  1  
492559  2016-12-16 08:55:00.000 2016-12-16 09:00:00.000  1  
492560  2016-12-16 09:00:00.000 2016-12-16 09:05:00.000  0  
492561  2016-12-16 09:05:00.000 2016-12-16 09:10:00.000  0  
492562  2016-12-16 09:10:00.000 2016-12-16 09:15:00.000  0  
492563  2016-12-16 09:15:00.000 2016-12-16 09:20:00.000  0  
492564  2016-12-16 09:20:00.000 2016-12-16 09:25:00.000  0  
492565  2016-12-16 09:25:00.000 2016-12-16 09:30:00.000  0  
492566  2016-12-16 09:30:00.000 2016-12-16 09:35:00.000  0  

这里保留8:45到9:00之间的时间,所以你不能接受它。 你也没有时间在8:25和8:35之间,所以你也不能保留它。举个例子,如果我想预约30分钟,那么我应该得到像这样的结果:

Min(ID) Max(ID) StartDate               EndDate
492560  492565  2016-12-16 09:00:00.000 2016-12-16 09:30:00.000

由于您没有足够的时间间隔

,因此只会返回1行

编辑2

感谢DVT,我已经修改了查询,我几乎有我的查询工作,这里唯一的hic是重叠时间。这是我的疑问:

DECLARE @newinterval INT = 60;

;with cte as (
SELECT
    t1.IdSchedulingByInterval AS IdSchedulingByIntervalMin
    , t2.IdSchedulingByInterval AS IdSchedulingByIntervalMax
    , t1.SchedulingByIntervalStartDate 
    , t2.SchedulingByIntervalEndDate
FROM
   RDV_tbSchedulingByInterval t1
    JOIN RDV_tbSchedulingByInterval t2 ON t2.SchedulingByIntervalStartDate = DATEADD(minute, @newinterval - 5, t1.SchedulingByIntervalStartDate)
    ) select * from cte where (select SUM(5) from RDV_tbSchedulingByInterval where IdSchedulingByInterval 
                                between cte.IdSchedulingByIntervalMin  and cte.IdSchedulingByIntervalMax ) = @newinterval
    order by cte.SchedulingByIntervalStartDate

这是我的结果:

492551  492562  2016-12-16 08:15:00.000 2016-12-16 09:15:00.000
492552  492563  2016-12-16 08:20:00.000 2016-12-16 09:20:00.000
492553  492564  2016-12-16 08:25:00.000 2016-12-16 09:25:00.000
492554  492565  2016-12-16 08:30:00.000 2016-12-16 09:30:00.000
492555  492566  2016-12-16 08:35:00.000 2016-12-16 09:35:00.000
492556  492567  2016-12-16 08:40:00.000 2016-12-16 09:40:00.000
492557  492568  2016-12-16 08:45:00.000 2016-12-16 09:45:00.000
492558  492569  2016-12-16 08:50:00.000 2016-12-16 09:50:00.000
492559  492570  2016-12-16 08:55:00.000 2016-12-16 09:55:00.000
492560  492571  2016-12-16 09:00:00.000 2016-12-16 10:00:00.000
492561  492572  2016-12-16 09:05:00.000 2016-12-16 10:05:00.000
492562  492573  2016-12-16 09:10:00.000 2016-12-16 10:10:00.000
492563  492574  2016-12-16 09:15:00.000 2016-12-16 10:15:00.000
492564  492575  2016-12-16 09:20:00.000 2016-12-16 10:20:00.000
492565  492576  2016-12-16 09:25:00.000 2016-12-16 10:25:00.000
492566  492577  2016-12-16 09:30:00.000 2016-12-16 10:30:00.000
492567  492578  2016-12-16 09:35:00.000 2016-12-16 10:35:00.000
492568  492579  2016-12-16 09:40:00.000 2016-12-16 10:40:00.000
492569  492580  2016-12-16 09:45:00.000 2016-12-16 10:45:00.000

预期结果:

492551  492562  2016-12-16 08:15:00.000 2016-12-16 09:15:00.000
492563  492574  2016-12-16 09:15:00.000 2016-12-16 10:15:00.000

我不希望时间重叠其他

7 个答案:

答案 0 :(得分:1)

由于您的会话持续时间可能会发生变化,因此这是一种稍微灵活的方法:

declare @t table (IDSchedulingByInterval int identity(1,1)
                    ,SchedulingByIntervalStartDate datetime
                    ,SchedulingByIntervalEndDate datetime
                    );
insert into @t(SchedulingByIntervalStartDate, SchedulingByIntervalEndDate)
values('2016-12-16 08:00:00.000','2016-12-16 08:05:00.000'),('2016-12-16 08:05:00.000','2016-12-16 08:10:00.000'),('2016-12-16 08:10:00.000','2016-12-16 08:15:00.000'),('2016-12-16 08:15:00.000','2016-12-16 08:20:00.000'),('2016-12-16 08:20:00.000','2016-12-16 08:25:00.000'),('2016-12-16 08:25:00.000','2016-12-16 08:30:00.000'),('2016-12-16 08:30:00.000','2016-12-16 08:35:00.000'),('2016-12-16 08:35:00.000','2016-12-16 08:40:00.000'),('2016-12-16 08:40:00.000','2016-12-16 08:45:00.000'),('2016-12-16 08:45:00.000','2016-12-16 08:50:00.000'),('2016-12-16 08:50:00.000','2016-12-16 08:55:00.000'),('2016-12-16 08:55:00.000','2016-12-16 09:00:00.000'),('2016-12-16 09:00:00.000','2016-12-16 09:05:00.000'),('2016-12-16 09:05:00.000','2016-12-16 09:10:00.000'),('2016-12-16 09:10:00.000','2016-12-16 09:15:00.000'),('2016-12-16 09:15:00.000','2016-12-16 09:20:00.000'),('2016-12-16 09:20:00.000','2016-12-16 09:25:00.000'),('2016-12-16 09:25:00.000','2016-12-16 09:30:00.000'),('2016-12-16 09:30:00.000','2016-12-16 09:35:00.000'),('2016-12-16 09:35:00.000','2016-12-16 09:40:00.000'),('2016-12-16 09:40:00.000','2016-12-16 09:45:00.000'),('2016-12-16 09:45:00.000','2016-12-16 09:50:00.000'),('2016-12-16 09:50:00.000','2016-12-16 09:55:00.000'),('2016-12-16 09:55:00.000','2016-12-16 10:00:00.000');

declare @Interval int = 15; -- This is the number of minutes for each session.  Must be divisible by 5 as base data is at a 5 minute granualarity.

select s.IDSchedulingByInterval as MinIDSchedulingByInterval
        ,e.IDSchedulingByInterval as MaxIDSchedulingByInterval
        ,s.SchedulingByIntervalStartDate
        ,e.SchedulingByIntervalEndDate
from @t s
    left join @t e  -- Find the corresponding end time for the session's start time
        on(dateadd(minute,@Interval,s.SchedulingByIntervalStartDate) =  e.SchedulingByIntervalEndDate)
where datediff(minute
                ,(select min(SchedulingByIntervalStartDate) from @t)
                ,s.SchedulingByIntervalStartDate
                ) % @Interval = 0;      -- This is the check that start time is at the start of one of your defined intervals.

已更新,包括不可用时段的逻辑:

declare @t table (IDSchedulingByInterval int identity(1,1)
                    ,SchedulingByIntervalStartDate datetime
                    ,SchedulingByIntervalEndDate datetime
                    ,Reserved bit
                    );
insert into @t(SchedulingByIntervalStartDate, SchedulingByIntervalEndDate,Reserved)
values('2016-12-16 08:00:00.000','2016-12-16 08:05:00.000',0),('2016-12-16 08:05:00.000','2016-12-16 08:10:00.000',0),('2016-12-16 08:10:00.000','2016-12-16 08:15:00.000',0),('2016-12-16 08:15:00.000','2016-12-16 08:20:00.000',0),('2016-12-16 08:20:00.000','2016-12-16 08:25:00.000',0),('2016-12-16 08:25:00.000','2016-12-16 08:30:00.000',0),('2016-12-16 08:30:00.000','2016-12-16 08:35:00.000',0),('2016-12-16 08:35:00.000','2016-12-16 08:40:00.000',0),('2016-12-16 08:40:00.000','2016-12-16 08:45:00.000',0),('2016-12-16 08:45:00.000','2016-12-16 08:50:00.000',1),('2016-12-16 08:50:00.000','2016-12-16 08:55:00.000',1),('2016-12-16 08:55:00.000','2016-12-16 09:00:00.000',1),('2016-12-16 09:00:00.000','2016-12-16 09:05:00.000',0),('2016-12-16 09:05:00.000','2016-12-16 09:10:00.000',0),('2016-12-16 09:10:00.000','2016-12-16 09:15:00.000',0),('2016-12-16 09:15:00.000','2016-12-16 09:20:00.000',0),('2016-12-16 09:20:00.000','2016-12-16 09:25:00.000',0),('2016-12-16 09:25:00.000','2016-12-16 09:30:00.000',0),('2016-12-16 09:30:00.000','2016-12-16 09:35:00.000',0),('2016-12-16 09:35:00.000','2016-12-16 09:40:00.000',0),('2016-12-16 09:40:00.000','2016-12-16 09:45:00.000',0),('2016-12-16 09:45:00.000','2016-12-16 09:50:00.000',0),('2016-12-16 09:50:00.000','2016-12-16 09:55:00.000',0),('2016-12-16 09:55:00.000','2016-12-16 10:00:00.000',0);

declare @Interval int = 60; -- This is the number of minutes for each session.  Must be divisible by 5 as base data is at a 5 minute granualarity.

with cte
as
(
    select s.IDSchedulingByInterval as MinIDSchedulingByInterval
            ,e.IDSchedulingByInterval as MaxIDSchedulingByInterval
            ,s.SchedulingByIntervalStartDate
            ,e.SchedulingByIntervalEndDate
    from @t s
        left join @t e  -- Find the corresponding end time for the session's start time
            on(dateadd(minute,@Interval,s.SchedulingByIntervalStartDate) =  e.SchedulingByIntervalEndDate)
    where datediff(minute
                    ,(select min(SchedulingByIntervalStartDate) from @t)
                    ,s.SchedulingByIntervalStartDate
                    ) % @Interval = 0       -- This is the check that start time is at the start of one of your defined intervals.
)
select c.MinIDSchedulingByInterval
        ,c.MaxIDSchedulingByInterval
        ,c.SchedulingByIntervalStartDate
        ,c.SchedulingByIntervalEndDate
from cte c
    left join @t t
        on(t.SchedulingByIntervalStartDate <= c.SchedulingByIntervalEndDate
            and t.SchedulingByIntervalEndDate > c.SchedulingByIntervalStartDate
            )
group by c.MinIDSchedulingByInterval
        ,c.MaxIDSchedulingByInterval
        ,c.SchedulingByIntervalStartDate
        ,c.SchedulingByIntervalEndDate
having sum(cast(t.Reserved as int)) = 0

答案 1 :(得分:1)

-- This converts the period to date-time format
SELECT 
    -- note the 15, the "minute", and the starting point to convert the 
    -- period back to original time
    DATEADD(minute, AP.FifteenMinutePeriod * 15, '2010-01-01T00:00:00') AS Period,
    AP.AvgValue
FROM
    -- this groups by the period and gets the average
    (SELECT
        P.FifteenMinutePeriod,
        AVG(P.Value) AS AvgValue
    FROM
        -- This calculates the period (fifteen minutes in this instance)
        (SELECT 
            -- note the division by 15 and the "minute" to build the 15 minute periods
            -- the '2010-01-01T00:00:00' is the starting point for the periods
            datediff(minute, '2010-01-01T00:00:00', T.Time)/15 AS FifteenMinutePeriod,
            T.Value
        FROM Test T) AS P
    GROUP BY P.FifteenMinutePeriod) AP

答案 2 :(得分:1)

这处理可变的分钟间隔。请注意,这尚未经过性能测试:

var onlineState,
    origOnLineProp;

beforeEach(function() {
    // Remember original config
    origOnLineProp = Object.getOwnPropertyDescriptor(Navigator.prototype, "onLine");

    onlineState = true;

    // New behavior
    Object.defineProperty(Navigator.prototype, "onLine", {
        enumerable: origOnLineProp.enumerable,
        configurable: origOnLineProp.configurable,
        get: function() { return  onlineState }
    });
});

it("...", function() {
    onlineState = false;
    expect("code").toBe("correctly functioning in offline mode");
});

afterEach(function() {
    // Restore original behavior
    Object.defineProperty(Navigator.prototype, "onLine", {
        enumerable: origOnLineProp.enumerable,
        configurable: origOnLineProp.configurable,
        get: origOnLineProp.get
    });
});

答案 3 :(得分:1)

这是我能提出的最简单的方法

;WITH Tally AS
 (
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS N FROM master.sys.objects A, master.sys.objects B
 )
,Intervals AS
(
    SELECT
    N AS Id,
    DATEADD(MINUTE, (N-1)*5, '20160101') AS StartDate,
    DATEADD(MINUTE, (N)*5, '20160101') AS EndDate
    FROM Tally
)

SELECT MIN(Id) AS MinId, MAX(Id) AS MaxId, MIN(StartDate), MAX(EndDate) FROM Intervals
GROUP BY CAST(StartDate AS Date), DATEPART(HOUR,StartDate), DATEPART(MINUTE, StartDate) / 15
ORDER BY MinId

修改

只需用您的表替换名称,如

SELECT 
MIN(IdSchedulingByInterval) AS MinId, 
MAX(IdSchedulingByInterval) AS MaxId, 
MIN(SchedulingByIntervalStartDate), ¨
MAX(SchedulingByIntervalEndDate) 
FROM RDV_tbSchedulingByInterval 
GROUP BY CAST(SchedulingByIntervalStartDate AS Date), DATEPART(HOUR,SchedulingByIntervalStartDate), DATEPART(MINUTE, SchedulingByIntervalStartDate) / 15
ORDER BY MinId

答案 4 :(得分:1)

我认为您可以使用如下查询:

SELECT MIN(ID) AS minID, MAX(ID) AS maxID, 
       MIN(StartDate) AS StartDate, MAX(EndDate) AS EndDate
FROM (
   SELECT ID, StartDate, EndDate,       
          ROW_NUMBER() OVER (ORDER BY StartDate) - 
          ROW_NUMBER() OVER (PARTITION BY x.v
                             ORDER BY StartDate) AS grp
   FROM mytable
   CROSS APPLY (SELECT CAST(CONVERT(DATE, EndDate) AS VARCHAR(10)) + 
                       CAST(DATEPART(HOUR, StartDate) AS VARCHAR(10)) + 
                       CAST(DATEPART(MINUTE, StartDate) / 15 AS VARCHAR(10))) AS x(v)) AS t
GROUP BY t.grp                                              
ORDER BY EndDate

答案 5 :(得分:0)

DECLARE @newinterval INT = 15;

SELECT
    t1.IdSchedulingByInterval AS IdSchedulingByIntervalMin
    , t2.IdSchedulingByInterval AS IdSchedulingByIntervalMax
    , t1.SchedulingByIntervalStartDate 
    , t2.SchedulingByIntervalEndDate
FROM
    <table> t1
    JOIN <table> t2 ON t2.SchedulingByIntervalStartDate = DATEADD(minute, @newinterval - 5, t1.SchedulingByIntervalStartDate)
WHERE
    DATEPART(minute,t1.SchedulingByIntervalStartDate) % @newinterval = 0;

答案 6 :(得分:0)

我能想到的最简单的查询..

    select MIN(ID), MAX(ID), MIN(StartDate), MAX(EndDate)
    from 
        (
        select 
            ID,
            case
               when substring(CONVERT(varchar, StartDate),16,2)in ('00','05','10') then 1
               when substring(CONVERT(varchar, StartDate),16,2)in ('15','20','25') then 2
               when substring(CONVERT(varchar, StartDate),16,2)in ('30','35','40') then 3
               when substring(CONVERT(varchar, StartDate),16,2)in ('45','50','55') then 4
            end as MinOfDate,
            substring(CONVERT(varchar, StartDate),13,2)as HourOfDate,
            substring(CONVERT(varchar, GETDATE()),1,6) as DayOfDate
            StartDate,
            EndDate
        from SourceTable
        where IsReserved = 0
        ) t
    group by DayOfDate,HourOfDate,MinOfDate