将日期范围拆分为t-sql中每个间隔的间隔和计数秒

时间:2010-06-24 07:41:39

标签: sql-server tsql

我正在尝试在一个表上创建一个查询,该表为具有开始时间和结束时间的人提供了多个条目,例如:

名,STARTIME,结束时间
('richard','2010-04-21 08:01:15','2010-04-21 08:06:15'),
('bill','2010-04-21 08:07:45','2010-04-21 08:11:15')

我需要做的是创建一个报告,显示每个5分钟间隔内每个条目的秒数,例如

名称,时间,秒
------------------
理查德,8:00225
理查德,8:05,75
法案,8:05135
纸币,8:10,75

因此查询必须创建这些间隔,然后计算每条记录的秒数,以显示该间隔中的总秒数。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

这是一个迭代解决方案,可以在开始时间在结束时间之前的任何时间段内工作。您没有指定是否要保留日期组件,以便在不同日期的当天早上8点报告时间间隔,或者是否要对它们进行分组。通过将我的解决方案中的time_bucket列转换为varchar然后将substring转换为varchar,然后将该varchar分组,然后将该组中的秒数相加,就可以很容易地丢弃日期组件。

如果您正在按时间段进行分析,那么您应该有一个时间桶维度表,类似于Lieven在其解决方案中提出的建议。这解决了你的基数问题。没有它,你必须做这样的事情:

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

答案 1 :(得分:0)

以下脚本可以帮助您入门。

虽然有一些警告提示

  • 如果starttime和endtime不是同一天,它在当前形式下不起作用
  • 没有检查,其中起始时间小于终止时间

SQL脚本

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