我需要計算數據庫中事件的「活動分鐘數」。開始時間是衆所周知的。計算兩個日期之間以分鐘計的時間差(僅工作小時數)
的複雜性在於,這些活性分鐘應該只在工作日期間進行計數 - 週一至週五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