我正在尝试编写一个SQL查询(SQL Server),其中一部分是确定两个日期时间之间每小时的分钟数。
例如:11/1/2018 09:05-11/1/2018 13:15
小时09:55分钟
10小时:60分钟
11小时:60分钟
12小时:60分钟
13小时:15分钟
然后将它们放入临时表中,并与其他一些数据分组,然后将这些数据用于根据这些分钟来计算美元金额。
是否有一种方法可以通过SQL完成不太慢或很费力的事情?
谢谢!
答案 0 :(得分:1)
我认为递归CTE可能是最好的方法:
with cte as (
select startTime, endTime,
startTime_hour as hourStart,
(case when endTime < dateadd(hour, 1, startTime_hour) then endTime
else dateadd(hour, 1, startTime_hour)
end) as hourEnd
from (select t.*,
dateadd(hour, datediff(hour, 0, startTime), 0) as startTime_hour
from t
) t
union all
select startTime, endTime,
dateadd(hour, 1, hourStart) as hourStart,
(case when endTime < dateadd(hour, 2, hourStart) then endTime
else dateadd(hour, 2, hourStart)
end) as endHour
from cte
where hourEnd < endTime
)
select cte.hourStart,
(case when hourStart > startTime then datediff(minute, hourStart, hourEnd) else datediff(minute, startTime, hourEnd) end) as minutes
from cte
order by hourStart;
Here是db <>小提琴。
答案 1 :(得分:0)
下面,我们将四个时间范围以及相关的值抽到表中。所有时间范围都不同,但前两个时间间隔为10h 30m。后两个相距9h 45m。
declare @times table (
startTime time,
endTime time,
val float
);
insert @times values
('2018-10-01 01:00:00', '2018-10-01 10:45:00', 7),
('2018-10-02 01:00:00', '2018-10-02 10:45:00', 8),
('2018-10-01 01:00:00', '2018-10-01 11:30:00', 1),
('2018-10-02 01:00:00', '2018-10-02 11:30:00', 3);
您可以根据需要使用“ datediff”功能进行汇总。使用取模运算符可以将您的分钟数转换为仅折扣整个小时数后剩余的分钟数。
select ap.h,
ap.m,
sumVal = sum(val)
from @times
cross apply (select
h = datediff(hour, startTime, endTime),
m = datediff(minute, startTime, endTime) % 60
) ap
group by ap.h,
ap.m
答案 2 :(得分:0)
这是替代的动态解决方案,您只能使用两个参数(开始/结束日期):
create table #temp
([hour] int, [minutes] int)
declare @startTime datetime='11/1/2018 09:05'
declare @EndTime datetime='11/1/2018 13:15'
declare @tempStartTime datetime = @startTime
declare @nextTimeRounded datetime
declare @hourdiff int = DATEDIFF(HOUR,@startTime,@EndTime)
declare @counter int = DATEPART(HH,@startTime)
declare @limit int = @counter + @hourdiff + 1
while @counter < @limit
begin
insert into #temp ([hour]) values (@counter)
set @nextTimeRounded= (dateadd(hour,
1 + datepart(hour, @tempStartTime),
cast(convert(varchar(10),@tempStartTime, 112) as datetime))
)
if @nextTimeRounded > @EndTime
begin
set @nextTimeRounded = @EndTime
end
update #temp
set [minutes] = (case when DATEDIFF(MINUTE,@tempStartTime,@nextTimeRounded)=0 then 60 else DATEDIFF(MINUTE,@tempStartTime,@nextTimeRounded) end)
where [hour] = @counter
set @counter = @counter + 1
set @tempStartTime = DATEADD(MINUTE,DATEDIFF(MINUTE,@tempStartTime,@nextTimeRounded),@tempStartTime);
end
select * from #temp