日期:2014-05-18  浏览次数:20384 次

新手问题:给定时间在给定时间段中的长度?
SQL code

/*
要求:对于任意两个时间(可能同一天,也可能间隔一天),计算它们在给定时间段[ss,ee]里的时间长度。。

下面的自定义函数基本思路是将start_time和end_time截取小时分钟转为int形式,再与ss,ee做比较,分类讨论。

现在的问题是:不能实现间隔一天的情况,如何更改呢?
*/

if object_id('temp') is not null
    drop table temp
go

--ss和ee列,以0到2400(间隔为100)依次表示00:00到24:00(次日凌晨)
create table temp(start_time datetime,end_time datetime,ss int,ee int)
go
insert into temp values('2011-12-20 22:10:00','2011-12-20 23:15:00',1000,2400);
insert into temp values('2011-11-01 00:15:00','2011-11-01 05:13:00',0,200);
insert into temp values('2011-11-01 05:15:00','2011-11-01 06:13:00',400,700);
insert into temp values('2011-10-20 23:45:00','2011-10-21 05:20:00',2200,2400);
insert into temp values('2011-10-20 23:45:00','2011-10-21 08:20:00',0,200);
insert into temp values('2011-10-20 17:45:00','2011-10-21 08:20:00',2200,2400);
go

if object_id('dbo.fgetperiod') is not null
    drop function dbo.fgetperiod
go

create function fgetperiod(@start_time_0 datetime,@end_time_0 datetime,@ss int,@ee int)
returns bigint 
as 
begin
declare @period int,@start_time int,@end_time int

select @start_time=replace(substring(convert(char,@start_time_0,120),charindex(':',@start_time_0)-2,5),':','')
select @end_time=replace(substring(convert(char,@end_time_0,120),charindex(':',@end_time_0)-2,5),':','')

if @start_time<=@ss 
begin
    if @end_time<=@ee
    begin
        if @end_time>=@ss
            select @period=(@end_time/100*60+@end_time%100)-(@ss/100*60+@ss%100)
        else
            select @period=0            
    end
    else 
        select @period=(@ee/100*60+@ee%100)-(@ss/100*60+@ss%100)    
end

else
begin
    if @end_time<=@ee
    begin
        if @end_time>=@ss
            select @period=(@end_time/100*60+@end_time%100)-(@start_time/100*60+@start_time%100)
        else
            select @period=0            
    end
    else
        select @period=(@ee/100*60+@ee%100)-(@start_time/100*60+@start_time%100)
end    

return @period
end
go

--调用自定义函数
select * 
    ,replace(substring(convert(char,start_time,120),charindex(':',start_time)-2,5),':','') as st
    ,replace(substring(convert(char,end_time,120),charindex(':',end_time)-2,5),':','') as en
    ,dbo.fgetperiod(start_time,end_time,ss,ee) as period
from temp 




------解决方案--------------------
SQL code

create table temp(start_time datetime,end_time datetime,ss int,ee int)
go
insert into temp values('2011-12-20 22:10:00','2011-12-20 23:15:00',1000,2400);
insert into temp values('2011-11-01 00:15:00','2011-11-01 05:13:00',0,200);
insert into temp values('2011-11-01 05:15:00','2011-11-01 06:13:00',400,600);
insert into temp values('2011-10-20 23:45:00','2011-10-21 05:20:00',2200,2400);
insert into temp values('2011-10-20 23:45:00','2011-10-21 08:20:00',0,200);
insert into temp values('2011-10-20 23:45:00','2011-10-23 08:20:00',2200,2400);
go

;with ach as
(
    select a.start_time,a.end_time,ss,ee,
        dateadd(dd,b.number,
            (case when b.number <> 0 then convert(datetime,convert(varchar(8),a.start_time,112))
                    else a.start_time end)) fact_start
    from temp a,master..spt_values b
    where b.[type] = 'p' and b.number between 0 and datediff(dd,a.start_time,a.end_time)
),art as
(
    select start_time,end_time,ss,ee,
        convert(datetime,convert(varchar(11),fact_start,120)+
                    (case when ss/100 in (24,0) then '00' else right(100+ss/100,2) end)+':'
                    +right(100+ss%100,2)) new_start,
        dateadd(dd,(case when ee/100=24 then 1 else 0 end),
                convert(datetime,convert(varchar(11),fact_start,120)+
                    (case when ee/100 in (24,0) then '00' else right(100+ee/100,2) end)+':'
                    +right(100+ee%100,2))) new_end
    from ach
)

select start_time,end_time,ss,ee,