2010-01-06 116 views
3

我正在爲現有應用程序添加一些新功能(數據庫是Microsoft SQL 2005)。基本上,我試圖計算特定部門在特定日期範圍內「無人」的分鐘數(或秒數)。我希望用一個語句理想地查詢數據集。我有一個循環遍歷記錄集的例程,解析它並吐出一個答案,但它非常難看。有沒有人有任何建議,我可以優化它的可讀性,使用純SQL - 甚至任何指針/我應該看的文章,我的Googlefu是讓我失望。在日期/時間範圍內計算數據集之外的總時間

我想在某些方面,這幾乎就像一個日曆的「空閒時間」搜索,但聚合。

這裏是一個模擬樣本數據集,讓您瞭解我正在處理的內容(有效地同事進入時鐘,然後計時)。爲了簡單起見,我使用的是四捨五入到幾分鐘,但我可能會在幾秒鐘內計算。

------------------------------------------------------------------------ 
| Colleague Id | Department Id | Date In   | Date Out   | 
------------------------------------------------------------------------ 
| 1   | 1    | 04/01/2010 08:45 | 04/01/2010 11:45 | 
| 2   | 1    | 04/01/2010 09:00 | 04/01/2010 12:15 | 
| 3   | 1    | 04/01/2010 10:00 | 04/01/2010 12:00 | 
| 4   | 1    | 04/01/2010 12:30 | 04/01/2010 17:00 | 
| 1   | 1    | 04/01/2010 12:45 | 04/01/2010 17:15 | 
| 3   | 1    | 04/01/2010 13:00 | 04/01/2010 17:25 | 
| 5   | 2    | ...    | ...    | 
------------------------------------------------------------------------ 

因此,例如,如果我查詢上表中爲部門ID = 1,04/01/2010 8時三十分00秒04/01/2010 17點30分○○秒之間,我期望的結果是35分鐘(或2100秒)「無人駕駛時間」(這是無人駕駛的範圍的開始,中間和結束時間的總和)。

回答

3

我有一個表已經創建的整數,我用這樣的東西。

鑑於這種情況,你想:

drop table foo 
go 

create table foo (
    c_id int not null, 
    d_id int not null, 
    datein datetime not null, 
    dateout datetime not null 
) 
go 


insert into foo values (1, 1, '04/01/2010 08:45', '04/01/2010 11:45') 
insert into foo values (2, 1, '04/01/2010 09:00', '04/01/2010 12:15') 
insert into foo values (3, 1, '04/01/2010 10:00', '04/01/2010 12:00') 
insert into foo values (4, 1, '04/01/2010 12:30', '04/01/2010 17:00') 
insert into foo values (1, 1, '04/01/2010 12:45', '04/01/2010 17:15') 
insert into foo values (3, 1, '04/01/2010 13:00', '04/01/2010 17:25') 
go 


drop procedure unmanned 
go 

create procedure unmanned 
    @d_id int, 
    @start datetime, 
    @end datetime 

as 

select distinct dateadd(ss,i_int,@start) 
from Integers 
     left join foo on dateadd(ss,i_int,@start) >= datein and dateadd(ss,i_int,@start) < dateout 


where i_int between 0 and 60*60*24 
and dateadd(ss,i_int,@start) >= @start and dateadd(ss,i_int,@start)< @end 
and datein is null 
order by 1 

go 

exec unmanned 1, '4/1/10 8:30', '4/1/10 17:30' 
1

這是一個範圍交集的問題:您現在看到的一些範圍:

4/01/2010 08:30:00 - 04/01/2010 17:30:00 

這個範圍可以表示爲數字 - 微秒,或從當天開始秒,例如:

[1000000, 3000000] 

,你想找到它不與任何碰撞的部位:

[1200000, 1250000] 
[1250000, 1490000] 
[1500000, 1950000] 
... 

當轉換爲數字格式時,它可以用幾乎任何語言實現。

編輯:

有大約日期範圍很大圖示和說明here一個很有趣的討論。

+0

感謝亞當鏈接這些項目進一步閱讀,非常有趣! – benno 2010-01-07 15:06:57

0

我推薦使用埃裏克·H公司的做法。有了這個免責聲明,這是有點討厭,但它確實提供了一種做同樣的事情的手段,如果你由於某種原因沒有訪問數字表。我敢肯定,這可以提高,我只是覺得想出來的W/O使用數字表:

Declare @Start DateTime, @End DateTime 

Select @Start = '04/01/2010 09:30' 
    , @End = '04/01/2010 17:30' 

--Table Creation Stuff 
Declare @y Table (ColleagueId Int, DepartmentId Int, DateIn DateTime, DateOut DateTime) 

Insert @y 
Select 1, 1, '04/01/2010 08:45' , '04/01/2010 11:45' 
Union All Select 2 , 1, '04/01/2010 09:00' , '04/01/2010 12:15' 
Union All Select 3 , 1, '04/01/2010 10:00' , '04/01/2010 12:00' 
Union All Select 4 , 1, '04/01/2010 12:30' , '04/01/2010 17:00' 
Union All Select 1 , 1, '04/01/2010 12:45' , '04/01/2010 17:15' 
Union All Select 3 , 1, '04/01/2010 13:00' , '04/01/2010 17:25' 
--------- 

Select DateDiff(minute, @Start, @End) -- TotalTime 
    - Sum(DateDiff(minute, 
     Case When DateIn < @Start Then @Start Else DateIn End, 
     Case When DateOut > @End Then @End Else DateOut End)) --StaffedTime 
    as UnmannedTime 
From 
(
    Select Min(din) DateIn, dout DateOut 
    From 
    (
     Select Min(y.DateIn) din, Max(y2.DateOut) dout 
     From @y y 
     Inner Join @y y2 on y.DateOut >= y2.DateIn 
     --you probably want to close the other end of these filters, but leave some room 
     --(to handle the guy who started @ 7:45, etc...) 
     Where y.DateIn < @End 
      and y2.DateOut > @Start    
     Group By y.DateIn 
    ) x 
    Group By dout 
) q 

編輯加入上面的case語句來處理StaffedTime的計算,當某一特定時期開始之前到@Start(或結束@End)

+0

謝謝AlexCuse,我採用了Eric H的方法,但是你提供了一個有趣的實現。 – benno 2010-01-07 15:08:39

+0

很高興你能夠使用數字表方法,我常常驚訝於聽到人們無法做到(因爲他們正在與供應商數據庫合作,或者他們害怕要求DBA增加一個;) ) – AlexCuse 2010-01-07 18:03:46

+0

根據您使用存儲過程的頻率,您可以使用笛卡爾連接隨時創建數字表....... – 2010-01-08 13:47:47