2013-10-14 94 views
1

我有中級SQL技能,但這是我嘗試過的最複雜的查詢。解決複雜查詢的構建

我的目標是建立一個查詢,該查詢將顯示任意一天中有多少分鐘,一組6個驅動器正在使用或閒置。正在使用的驅動器正在將備份寫入磁帶,即運行作業。驅動器一次只能處理作業。駕駛員可能會在同一天開始和結束一項工作,或者如果這是一項艱鉅的工作,那麼可以在一天後開始並在兩天後結束。最重要的是,我能夠報告每個驅動器的分鐘數,無論是UP還是IDLE(兩者都很重要),並且只報告它在相應日期的工作分鐘數,即使這項工作進入下一個分析階段。

所以,從以下

  1. 複雜結果我不能只減去結束時間開始時間和總和一個特定的驅動器上運行的所有作業的運行時間,因爲很多作業跨越午夜,我必須將工作分鐘分配到他們發生的那一天。 IE瀏覽器。我無法報告一個驅動器在24小時內完成了50個小時的工作,僅僅因爲工作的結束時間爲2天。

  2. 開始時間和結束時間欄均爲UTC時間,並且必須轉換爲PST。

  3. 我需要佔位符分配當天的任何一個驅動器空閒時間,這樣我就可以顯示每個驅動器的空閒時間。

我需要放在一起的表是隻有兩個:

  1. 一個時間日曆表。從10-10-2009到10-07-2021開始的每一分鐘都有一排。

  2. 一個表格,包含已完成的所有作業的開始和結束時間,運行它們的驅動器的名稱以及作業的名稱。

這裏的DDL包含了自2009年以來一天的每一分鐘一列日曆表到2014

WITH e1(min) AS(
    SELECT * FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))x(n) 
), 
e2(min) AS(
    SELECT e1.min FROM e1, e1 x 
), 
e4(min) AS(
    SELECT e2.min FROM e2, e2 x 
), 
e8(min) AS(
    SELECT e4.min FROM e4, e4 x 
), 
cteTally(min) AS(
    SELECT TOP 6307204 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1 
    FROM e8 
), 
Test(min) AS(
SELECT DATEADD(minute, min, DATEADD(YEAR, -2, GETDATE())) 
FROM cteTally) 
SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, 0, DATEADD(YEAR, -2, GETDATE())), 0) 
FROM Test 
WHERE min <= DATEADD(YEAR, 10, GETDATE()) 

下面是包含設備/工作表樣品DDL /啓動&結束時間。

CREATE TABLE JobHistorySummary 
(JobName nvarchar(255), 
ActualStartTime datetime, 
EndTime datetime, 
DeviceName nvarchar(128)) 
INSERT INTO JobHistorySummary 
VALUES 
('FOAMTools E: Weekly - FULL', '2013-08-04 03:20:00.000', '2013-08-04 20:20:00.000', '1 Drv'), 
('HRDuplex D: Weekly - FULL', '2013-08-04 18:26:00.000', '2013-08-05 13:00:00.000', '2 Drv'), 
('HRDuplex D: Daily - INC', '2013-08-04 20:44:00.000', '2013-08-05 15:50:00.000', '1 Drv'), 
('PayNROLL C: Weekly - FULL', '2013-08-04 00:00:00.000', '2013-08-06 15:40:00.000','3 Drv'), 
('PayNROLL C: Daily - INC', '2013-08-05 06:30:00.000', '2013-08-05 06:50:00.000', '4 Drv'), 
('SmallIBM F: Daily - FULL', '2013-08-04 00:30:00.000', '2013-08-04 06:30:00.000', '5 Drv'), 
('BigIBM F: Daily - INC', '2013-08-06 12:30:00.000', '2013-08-06 12:50:00.000', '6 Drv'); 

計算需要得到本地時間爲[ActualStartTime] + GETDATE() - GETUTCDATE())

即使我只需要兩個表,我想不出加入他們的邏輯以便它們爲驅動器處於空閒狀態的日期創建NULL佔位符。我想用NULL值作爲每個驅動器的空閒分鐘數。此外,我無法弄清楚如何將使用時間分爲發生的那一天......意味着每個驅動器每天不超過1440分鐘的工作時間,即使是午夜的工作也是如此。第二天的分鐘數分配爲相應的驅動器在第二天工作的分鐘數。

+0

單個設備是否有可能同時運行多個作業? –

+0

我建議在SO上搜索TDQD;你會發現很多例子(大約22),我使用了測試驅動的查詢設計來逐步構建查詢。你需要使用這個問題答案中提出的想法。 –

+0

UTC日期到當地時間的轉換是否需要考慮夏令時?如果是這樣,那麼在夏令時開始或結束時,如何報告工作的持續時間? –

回答

0

以下顯示如何生成每臺設備每天使用的時間。空閒時間只是24減去。假設您已經生成了表中所有日期的表格,我們可以使用Date類型的一個字段dt調用該Cal。 (容易做到)。以下給出了一般方法。

select devicename, cal.dt, sum(time(least(actualendtime, cal.dt)- time(actualstarttime)) 
from JobHistorySummary jhs inner join cal 
on (jhs.actualstarttime >= cal.dt and jhs.actualendtime < cal.dt) 
group by devicename, cal.dt 

現在你已經使用了上面使用轉換時間的同樣的語句,並假設cal是在轉換後的時區。

select devicename, cal.dt, sum(time(least(convert_tz(actualendtime,'UTC','US/Pacific'), cal.dt)- time(convert_tz(actualstarttime,'UTC','US/Pacific'))) 
from JobHistorySummary jhs inner join cal 
on (convert_tz(actualstarttime,'UTC','US/Pacific') >= cal.dt and convert_tz(actualendtime,'UTC','US/Pacific') < cal.dt) 
group by devicename, cal.dt 

但上述內容也不正確,因爲mysql不會在時間值上正確地進行減法和彙總求和。所以你需要使用更類似的東西:

select devicename, cal.dt, econd_to_time(sum(time_to_second(timediff(time(least(actualendtime, cal.dt), time(actualstarttime))))) 
from JobHistorySummary jhs inner join cal 
on (jhs.actualstarttime >= cal.dt and jhs.actualendtime < cal.dt) 
group by devicename, cal.dt