Разбить диапазон дат на интервалы и считать секунды в каждом интервале в t-sql - PullRequest
1 голос
/ 24 июня 2010

У меня есть запрос, который я пытаюсь сделать для таблицы с несколькими записями для людей с начальным и конечным временем, например ::100100

имя, СтарТайм, время окончания
(«Ричард», «2010-04-21 08:01:15», «2010-04-21 08:06:15»),
(«Счет», «2010-04-21 08:07:45», «2010-04-21 08:11:15»)

Что мне нужно сделать, так это создать отчет, показывающий секунды каждой записи в каждом 5-минутном интервале, например,

имя, время, секунды
------------------
ричард, 8: 00225
ричард, 8: 05,75
Счет, 8: 05135
Счет, 8: 10,75

Таким образом, запрос должен создать эти интервалы, а затем подсчитать секунды для каждой записи, чтобы показать общее количество секунд в этом интервале. Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 24 июня 2010

Вот итеративное решение, которое будет работать в течение любого периода времени, когда время начала раньше времени окончания.Вы не указали, хотите ли вы, чтобы компонент даты для отчетных интервалов времени в разные дни в 8 часов утра находился на другой строке, или же вы хотите сгруппировать их.Было бы довольно легко отказаться от компонента даты, преобразовав столбец time_bucket в моем решении в varchar, затем подстроку, сгруппировав по этому varchar, а затем сложив секунды в этой группе.

Если вы выполняете анализ по временитогда у вас, вероятно, должна быть таблица измерений временных интервалов, аналогичная той, что предлагает Ливен в своем решении.Это решает ваши проблемы кардинальности.Без этого вам пришлось бы делать что-то вроде этого:

create table #results
( name varchar(20) not null, time_bucket datetime not null, seconds int not null )

declare @name varchar(20), @startTime datetime, @endTime datetime, @timeBucket datetime, @secondsInBucket int
declare dataCur cursor for select * from source_data
open dataCur

fetch next from dataCur into @name, @startTime, @endTime
while @@fetch_status = 0
begin
    set @timeBucket = convert(datetime, convert(varchar(14), @startTime, 120) + convert(varchar(2), (datepart(mi, @startTime) / 5) * 5), 120)

    while @timeBucket < @endTime
    begin
        set @secondsInBucket = case
            when @timeBucket < @startTime then datediff(ss, @startTime, dateadd(mi, 5, @timeBucket))
            when @endTime < dateadd(mi, 5, @timeBucket) then datediff(ss, @timeBucket, @endTime)
            else 300
        end

        insert into #results values (@name, @timeBucket, @secondsInBucket)
        set @timeBucket = dateadd(mi, 5, @timeBucket)
    end

    fetch next from dataCur into @name, @startTime, @endTime
end

close dataCur
deallocate dataCur

select * from #results
0 голосов
/ 24 июня 2010

Следующий скрипт должен помочь вам начать.

Несколько предупреждений, хотя

  • он не работает в своей текущей форме, если время начала и окончания не совпадают
  • нет проверок на месте, если время начала меньше, чем время окончания

SQL Script

DECLARE @People TABLE (
  Name VARCHAR(32)
  , StartTime DATETIME
  , EndTime DATETIME
)

DECLARE @MinHour INTEGER
DECLARE @MaxHour INTEGER
DECLARE @Times TABLE (
  Hour INTEGER
  , Minute INTEGER
)

INSERT INTO @People
SELECT           'richard', '2010-04-21 08:01:15', '2010-04-21 08:06:15'
UNION ALL SELECT 'bill'   , '2010-04-21 08:07:45', '2010-04-21 08:11:15'


SELECT  @MinHour = MIN(DATEPART(hh, StartTime))
        , @MaxHour = MAX(DATEPART(hh, EndTime))
FROM    @People

WHILE @MinHour < @MaxHour + 1
BEGIN
  INSERT INTO @Times 
  SELECT @MinHour, 0
  UNION ALL SELECT @MinHour, 5
  UNION ALL SELECT @MinHour, 10
  UNION ALL SELECT @MinHour, 15
  UNION ALL SELECT @MinHour, 20
  UNION ALL SELECT @MinHour, 25
  UNION ALL SELECT @MinHour, 30
  UNION ALL SELECT @MinHour, 35
  UNION ALL SELECT @MinHour, 40
  UNION ALL SELECT @MinHour, 45
  UNION ALL SELECT @MinHour, 50
  UNION ALL SELECT @MinHour, 55
  SET @MinHour = @MinHour + 1
END

SELECT  p.Name
        , t.Hour
        , t.Minute
        , CASE WHEN DATEPART(mi, p.EndTime) - DATEPART(mi, p.EndTime) % 5  = t.Minute 
          THEN 60 * (DATEPART(mi, p.EndTime) % 5) + DATEPART(ss, p.EndTime)
          ELSE 300 - 60 * (DATEPART(mi, p.StartTime) % 5) - DATEPART(ss, p.StartTime)
          END
FROM    @People p
        INNER JOIN @Times t ON DATEPART(hh, p.StartTime) = t.Hour
                               AND DATEPART(hh, p.EndTime) = t.Hour
                               AND DATEPART(mi, p.StartTime) - DATEPART(mi, p.StartTime) % 5 <= t.Minute
                               AND DATEPART(mi, p.EndTime) - DATEPART(mi, p.EndTime) % 5 >= t.Minute
ORDER BY 
        p.Name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...