我需要计算数据库中事件的“活动分钟数”。开始时间是众所周知的。计算两个日期之间以分钟计的时间差(仅工作小时数)
的复杂性在于,这些活性分钟应该只在工作日期间进行计数 - 周一至周五9 am-6.30pm,不包括周末和假日天
启动或“当前”时间可(已知)名单在工作时间之外,但仍然只计算工作时间。
这是SQL Server 2005,因此可以使用T-SQL或托管程序集。
我需要计算数据库中事件的“活动分钟数”。开始时间是众所周知的。计算两个日期之间以分钟计的时间差(仅工作小时数)
的复杂性在于,这些活性分钟应该只在工作日期间进行计数 - 周一至周五9 am-6.30pm,不包括周末和假日天
启动或“当前”时间可(已知)名单在工作时间之外,但仍然只计算工作时间。
这是SQL Server 2005,因此可以使用T-SQL或托管程序集。
如果你想这样做纯粹的SQL这里有一个方法
CREATE TABLE working_hours (start DATETIME, end DATETIME);
现在填充工时表可数的时期,〜每年250行。
如果你有一个事件(@event_start,@event_end),将开始时间和结束掉小时,然后简单的查询
SELECT SUM(end-start) as duration
FROM working_hours
WHERE start >= @event_start AND end <= @event_end
就足够了。
如果在另一方面,事件的开始和/或在工作时间内结束查询比较复杂
SELECT SUM(duration)
FROM
(
SELECT SUM(end-start) as duration
FROM working_hours
WHERE start >= @event_start AND end <= @event_end
UNION ALL
SELECT [email protected]_start
FROM working_hours
WHERE @event_start between start AND end
UNION ALL
SELECT @event_end - start
FROM working_hours
WHERE @event_end between start AND end
) AS u
注:
编辑: 在MSSQL中,你可以使用DATEDIFF(MI,开始,结束)获得的分钟数为每个减法以上。
在全球范围内,你需要:
(注意,这个假设的情况下可以持续多天:是,真的有可能?)
不同的方法将有事件,检查是否每个时间里面一个滴答作响的时钟该事件应当在那个时间进行计数,并且在相关时段内每次发现自己活跃时增加(以秒或分钟为单位)。这仍然需要助手表,并且可能会更少审计(可能)。
如果通过迭代你的意思是使用游标(或其他基于行的算法),那么我不同意 - 这是没有必要的(见我的答案)。 – Unreason 2010-07-21 08:55:53
我来这里寻找一个非常类似的问题的答案 - 我需要得到两个日期之间的分钟,不包括周末,不包括08:30和18:00以外的时间。经过一些黑客攻击后,我想我已经排序了。以下是我如何做到的。想法是欢迎 - 谁知道,也许有一天我会注册这个网站:)
create function WorkingMinutesBetweenDates(@dteStart datetime, @dteEnd datetime)
returns int
as
begin
declare @minutes int
set @minutes = 0
while @dteEnd>[email protected]
begin
if datename(weekday,@dteStart) <>'Saturday' and datename(weekday,@dteStart)<>'Sunday'
and (datepart(hour,@dteStart) >=8 and datepart(minute,@dteStart)>=30)
and (datepart(hour,@dteStart) <=17)
begin
set @minutes = @minutes + 1
end
set @dteStart = dateadd(minute,1,@dteStart)
end
return @minutes
end
go
我认为这会很慢,因为它是一个循环。以上基于集合的方法可能是最好的;如果你不想使用表,那么sqlclr方法会更快。我有一个可以工作的sqlclr实现,它的速度非常快,但我们正在朝着基于集合的方法发展,以获得更多的可定义性 – 2011-04-27 09:32:48
我开始用什么非理性发布工作,是一个很好的开始。我测试了这是SQL Server,发现并非所有的时间都被捕获。我认为问题主要是当活动在同一天开始和结束时。该解决方案似乎是工作不够好,我
CREATE TABLE [dbo].[working_hours](
[wh_id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[wh_starttime] [datetime] NULL,
[wh_endtime] [datetime] NULL,
PRIMARY KEY CLUSTERED
(
[wh_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
走这剩下要做的就是填充工时表像
;WITH cte AS (
SELECT CASE WHEN DATEPART(Day,'2014-01-01 9:00:00 AM') = 1 THEN '2014-01-01 9:00:00 AM'
ELSE DATEADD(Day,DATEDIFF(Day,0,'2014-01-01 9:00:00 AM')+1,0) END AS myStartDate,
CASE WHEN DATEPART(Day,'2014-01-01 5:00:00 PM') = 1 THEN '2014-01-01 5:00:00 PM'
ELSE DATEADD(Day,DATEDIFF(Day,0,'2014-01-01 5:00:00 PM')+1,0) END AS myEndDate
UNION ALL
SELECT DATEADD(Day,1,myStartDate), DATEADD(Day,1,myEndDate)
FROM cte
WHERE DATEADD(Day,1,myStartDate) <= '2015-01-01'
)
INSERT INTO working_hours
SELECT myStartDate, myEndDate
FROM cte
OPTION (MAXRECURSION 0)
delete from working_hours where datename(dw,wh_starttime) IN ('Saturday', 'Sunday')
--delete public holidays
delete from working_hours where CAST(wh_starttime AS DATE) = '2014-01-01'
我的第一篇文章
CREATE FUNCTION [dbo].[udFWorkingMinutes]
(
@startdate DATETIME
,@enddate DATETIME
)
RETURNS INT
AS
BEGIN
DECLARE @WorkingHours INT
SET @WorkingHours =
(SELECT
CASE WHEN COALESCE(SUM(duration),0) < 0 THEN 0 ELSE SUM(Duration)
END AS Minutes
FROM
(
--All whole days
SELECT ISNULL(DATEDIFF(mi,wh_starttime,wh_endtime),0) AS Duration
FROM working_hours
WHERE wh_starttime >= @startdate AND wh_endtime <= @enddate
UNION ALL
--All partial days where event start after office hours and finish after office hours
SELECT ISNULL(DATEDIFF(mi,@startdate,wh_endtime),0) AS Duration
FROM working_hours
WHERE @startdate > wh_starttime AND @enddate >= wh_endtime
AND (CAST(wh_starttime AS DATE) = CAST(@startdate AS DATE))
AND @startdate < wh_endtime
UNION ALL
--All partial days where event starts before office hours and ends before day end
SELECT ISNULL(DATEDIFF(mi,wh_starttime,@enddate),0) AS Duration
FROM working_hours
WHERE @enddate < wh_endtime
AND @enddate >= wh_starttime
AND @startdate <= wh_starttime
AND (CAST(wh_endtime AS DATE) = CAST(@enddate AS DATE))
UNION ALL
--Get partial day where intraday event
SELECT ISNULL(DATEDIFF(mi,@startdate,@enddate),0) AS Duration
FROM working_hours
WHERE @startdate > wh_starttime AND @enddate < wh_endtime
AND (CAST(@startdate AS DATE)= CAST(wh_starttime AS DATE))
AND (CAST(@enddate AS DATE)= CAST(wh_endtime AS DATE))
) AS u)
RETURN @WorkingHours
END
GO
承滴盘!慈悲。
使用非理性的很好的起点,这里是SQL Server的一个TSQL实现2012
这第一个SQL填充表与我们的工作日期和时间,不包括周末和节假日:
declare @dteStart date
declare @dteEnd date
declare @dtStart smalldatetime
declare @dtEnd smalldatetime
Select @dteStart = '2016-01-01'
Select @dteEnd = '2016-12-31'
CREATE TABLE working_hours (starttime SMALLDATETIME, endtime SMALLDATETIME);
while @dteStart <= @dteEnd
BEGIN
IF datename(WEEKDAY, @dteStart) <> 'Saturday'
AND DATENAME(WEEKDAY, @dteStart) <> 'Sunday'
AND @dteStart not in ('2016-01-01' --New Years
,'2016-01-18' --MLK Jr
,'2016-02-15' --President's Day
,'2016-05-30' --Memorial Day
,'2016-07-04' --Fourth of July
,'2016-09-05' --Labor Day
,'2016-11-11' --Veteran's Day
,'2016-11-24' --Thanksgiving
,'2016-11-25' --Day after Thanksgiving
,'2016-12-26' --Christmas
)
BEGIN
select @dtStart = SMALLDATETIMEFROMPARTS(year(@dteStart),month(@dteStart),day(@dteStart),8,0) --8:00am
select @dtEnd = SMALLDATETIMEFROMPARTS(year(@dteStart),month(@dteStart),day(@dteStart),17,0) --5:00pm
insert into working_hours values (@dtStart,@dtEnd)
END
Select @dteStart = DATEADD(day,1,@dteStart)
END
现在这里是曾作为INT返回分钟的逻辑:
declare @event_start datetime2
declare @event_end datetime2
select @event_start = '2016-01-04 8:00'
select @event_end = '2016-01-06 16:59'
SELECT SUM(duration) as minutes
FROM
(
SELECT DATEDIFF(mi,@event_start,@event_end) as duration
FROM working_hours
WHERE @event_start >= starttime
AND @event_start <= endtime
AND @event_end <= endtime
UNION ALL
SELECT DATEDIFF(mi,@event_start,endtime)
FROM working_hours
WHERE @event_start >= starttime
AND @event_start <= endtime
AND @event_end > endtime
UNION ALL
SELECT DATEDIFF(mi,starttime,@event_end)
FROM working_hours
WHERE @event_end >= starttime
AND @event_end <= endtime
AND @event_start < starttime
UNION ALL
SELECT SUM(DATEDIFF(mi,starttime,endtime))
FROM working_hours
WHERE starttime > @event_start
AND endtime < @event_end
) AS u
这正确返回1分钟害羞三个9小时工作日内
+1如果计算可能会持续很多个工作日(并假定工作时间和假期相当稳定),我发现值得添加一个'julianized'工作时间列表(从任意时代到现在的总工作时间)。因此,除了UNIONing三个结果集然后进行SUM之外,您还可以对每个SUM进行相加,然后将它们加在一起,除非现在三个UNIONed结果集中的第一个的计算仅仅是减去两个值的情况(而不是求和因为它们已经被预先求和(存储不被计算),所以减去*所有*中间行)。 – onedaywhen 2010-07-21 09:29:54
辉煌......超过通过托管代码解决方案的一半 - 但这更好! – 2010-07-21 15:29:00