3

Я создаю сайт, на котором вы можете принять участие в онлайн-конференции. Я не буду объяснять все подробно, но у меня есть таблица с моим доступным временем, чтобы записаться на прием. Распределяется на интервалы 5 мин. Вот пример:SQL Server, как перегруппировать интервал 5 минут в 1 из 15 минут?

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 

В зависимости время консультации, основанные на причины для консультаций, я сгруппировать эти строки в одну и знать мин (IDSchedulingInterval) и максимальное (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 

Длительность можно изменить. Я не знаю, как это сделать.

EDIT Вот некоторые исключения, которые вы должны проверить. Вот мой стол

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 

только одна строка будет возвращена, потому что вы не имеете достаточно времени между другими интервалами

EDIT 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 

Я не хочу время перекрывается другой

+0

пожалуйста, напишите образец и ожидаемые результаты в виде текста – TheGameiswar

+0

@TheGameiswar образца первое изображение и ожидаемый результат вторая картина – alexandre

+0

изображения заблокированы в моем домене, а также размещение в виде текста помогает в подготовке данных образца: http: //meta.stackoverflow.com/questions/261455/imgur-com-blocked-what-are-my-options – TheGameiswar

ответ

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; 
+0

Хороший! Просто, чтобы знать, что, если у меня есть разное время, когда мне нужно изменить этот запрос? – alexandre

+0

Можете ли вы уточнить время изменения времени? – DVT

+0

Я имею в виду, что вы группируете 15-минутный интервал, но если мне нужно сгруппировать его на 30-минутный интервал, какой параметр я должен изменить, чтобы достичь этого с помощью вашего ответа. – alexandre

0

Как ваш продолжительность сеанса может измениться, вот slig htly более гибкий подход:

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 
+0

. Ваш запрос почти работает и быстро, но я тестирую его и единственная проблема У меня есть, если вам нужен интервал в 60 минут на пример, и у вас уже есть 15-минутный резерв времени в этом примере с пропуском: с 8:00 до 8:15 он зарезервирован, вы ответили на запрос по-прежнему 8:00 до 9:00 будет доступно – alexandre

+0

@alexandre Я обновил свой ответ, чтобы не возвращать периоды с забронированными слотами внутри них. – iamdave

+0

Это не работает, либо он дает мне интервал с 8:00 до 9:00, но в этом интервале у меня есть пробел, который составляет от 8:10 до 8:15, поэтому oyu не имеет полного интервала 60 минут – alexandre

0
-- 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 
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 
+0

Вы должны использовать функцию 'minute()', если вам нужно получить минутную часть из значения 'datetime', а не преобразовать ее в строку. – iamdave

+0

Справедливая точка зрения, но у меня были проблемы с функциями времени в прошлом и нашла преобразование строк более надежным. – Nambu14

+0

Проблемы, как что? – iamdave

0

Это обрабатывает переменную минут промежуток.Обратите внимание, это не было проверено выполнение:

DECLARE @MinuteInterval INT = 15 

SELECT  MIN(a.IdSchedulingByInterval) AS MinId, 
      MAX(aa.IdSchedulingByInterval) AS MaxId, 
      MIN(a.SchedulingByIntervalStartDate) AS StartDate, 
      MAX(aa.SchedulingByIntervalEndDate) AS EndDate 
FROM  Appointment a 
CROSS JOIN Appointment aa 
WHERE  DATEDIFF(MINUTE, a.SchedulingByIntervalStartDate, aa.SchedulingByIntervalEndDate) = @MinuteInterval 
GROUP BY a.IdSchedulingByInterval 
HAVING  DATEPART(MINUTE, MIN(a.SchedulingByIntervalStartDate)) % @MinuteInterval = 0 
+0

этот запрос слишком медленный, он занимает у меня всего 15 секунд только для выбора 5: $ – alexandre

+0

Достаточно честный, это риск с помощью CROSS JOINs. Сколько строк находится в исходной таблице? –

0

Это самый простой я мог придумать, не более специфических

;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 

EDIT:

Просто замените имена с таблицей как

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 
+0

Как я могу заставить его работать с моим столом? мое имя таблицы: RDV_tbSchedulingByInterval – alexandre

0

Я думаю, вы можете использовать запрос вроде следующего:

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 
+0

Это почти работает только с hic, это возможно, что есть недостающая строка, потому что некоторые ppl не захотят работать с 12h до 13h, потому что они запускаются, поэтому интервал 12h to 13 не появится или даже определенная строка будет зарезервировано уже другим назначением, но ваш запрос не стал бы смотреть на это – alexandre

+0

@alexandre Можете ли вы опубликовать некоторые примеры данных, демонстрирующих проблему? –

+0

Я редактировал свой вопрос с примером исключения – alexandre