2015-06-20 304 views
0

我在使用SQL查詢報告CNC監控系統的機器效率方面遇到了一些困難。監控軟件記錄機器處於不同狀態的持續時間,如加工,停止,失靈設置等。我希望每天爲每臺機器計算這些狀態的持續時間,以確定它們的效率。計算sql中兩個日期之間的持續時間

給出每個狀態的開始和結束時間我最初認爲這將是一個計算兩個日期之間差異的簡單情況,但並不那麼簡單。問題是一個國家可能會在一天後期開始,並在下一個凌晨結束,這使得很難計算每天的狀態持續時間。

下面是一個包含Excel文件的鏈接樣本數據 https://dl.dropboxusercontent.com/u/71259257/example%20dataset.xlsx

我想出了一個相當混亂的解決方案,我會以此爲基礎創建計劃存儲過程,輸出處理數據到一個單獨的表格。

這裏是我的查詢

DECLARE @date DATE; 
SET @Date= '16 June 2015'; 

SELECT 
    Name, State, 
    CASE 
     WHEN LEFT(CONVERT(VARCHAR, StartDate, 120), 10) = @Date 
      AND LEFT(CONVERT(VARCHAR, EndDate, 120), 10) = @Date 
      THEN dbo.CalculateReportDuration(StartDate, EndDate) 
    END as Duration 
FROM 
    [emc].[dbo].[TMB_MachineStateReport] 
WHERE 
    CONVERT(Date, StartDate) = @Date 
    AND CONVERT(Date, EndDate) = @Date 

UNION ALL 

SELECT 
    Name, State, 
    dbo.CalculateReportDuration(LEFT(CONVERT(VARCHAR, EndDate, 120), 10) + ' 00:00:00.0000000 +00:00', EndDate) as Duration 
FROM 
    [emc].[dbo].[TMB_MachineStateReport] 
WHERE 
    CONVERT(Date, EndDate) = @Date 
    AND CONVERT(Date, StartDate) < @Date 

UNION ALL 

SELECT 
    Name, State, 
    dbo.CalculateReportDuration(StartDate, LEFT(CONVERT(VARCHAR, StartDate, 120), 10) + ' 23:59:59.9999999 +00:00') 
FROM 
    [emc].[dbo].[TMB_MachineStateReport] 
WHERE 
    CONVERT(Date, EndDate) > @Date 
    AND CONVERT(Date, StartDate) = @Date 

我想知道的是,沒有任何人有任何更好的想法?理想情況下,我想創建視圖,但目前我依靠一個SQL變量來保存日期值,我將使用while循環遞增表中的所有日期。

代碼CalculateReportDuration功能

USE [emc] 
GO 
/****** Object: UserDefinedFunction [dbo].[CalculateReportDuration] Script Date: 06/20/2015 10:23:21 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
ALTER FUNCTION [dbo].[CalculateReportDuration] 
      (
       @start DATETIMEOFFSET(7), 
       @end DATETIMEOFFSET(7) 
      ) 
      RETURNS INT 
      AS 
      BEGIN 
       RETURN CAST(ROUND(DATEDIFF(SECOND, @start, @end)/60.0, 0) AS INT) 
      END 

任何幫助是極大你的兩個日期讚賞

+0

請提供示例輸入和期望輸出,對於最壞的情況,最好還提供SQL小提琴鏈接。 –

+0

好的會做的感謝 – user515031

+0

可以用多個記錄來替代午夜過去的記錄,而不是。按程序進行處理或使用計數表。如果您確實/可能需要原始記錄(跨越多天),請使用額外的表格進行拆分(加上最初在一天內的限制)。 - 從那裏,你應該善於使用視圖。 - 如果您正在控制原始輸入流,則可能需要再次切換到基於日期的記錄(取決於此任務要求的外部情況),而不是平行於多天的記錄。 (對不起,沒有代碼準備好。) – Abecee

回答

0

您可以簡單地使用DATEDIFF()

下面是一個簡單的例子:

SELECT DATEDIFF(minutes, GETDATE(), DATEADD(hours,2,GETDATE())) 

更多here

正如OP在評論中所述,他希望每天都有一排。這意味着時間應該每天分割,之後應該進行計算。

以下是實現此目的的代碼。請記住,由於它是通過CTE完成的,因此您應該瞭解超過100天的陳述。 ;-)否則你需要調整MAX_RECURSION

IF(OBJECT_ID(N'tempdb..#timing') IS NOT NULL) 
    DROP TABLE #timing 

-- Create demo data 
CREATE TABLE #timing(id int identity(1,1), startdate datetime, enddate datetime) 

INSERT INTO #timing(startdate, enddate) 
VALUES (DATEADD(day,-1,GETDATE()),DATEADD(MINUTE,10,GETDATE())), -- time spanning 1 day + 10 min 
     (DATEADD(MINUTE,-70,GETDATE()),GETDATE()), -- spanning the current date just over 70 minutes 
     (DATEADD(day,-3,GETDATE()),GETDATE()) -- spanning 3 days 

     SELECT t.startdate, t.enddate, CONVERT(date,t.startdate), CONVERT(date,t.enddate) FROM #timing as t 

;WITH cte AS(
    SELECT id, t.startdate as orig_startdate, t.enddate as orig_enddate, 
     t.startdate, 
     DATEADD(SECOND,-1,CONVERT(datetime,DATEADD(day,1,CONVERT(date,t.startdate)))) as enddate, 
     1 as iteration 
    FROM #timing as t 
    WHERE CONVERT(date, t.startdate) <> CONVERT(date, t.enddate) 
    UNION ALL 
    SELECT c.id, c.orig_startdate, c.orig_enddate, 
     CONVERT(datetime,DATEADD(day,c.iteration,CONVERT(date,c.orig_startdate))) as startdate, 
     CASE WHEN CONVERT(date,DATEADD(day,c.iteration,CONVERT(date,c.orig_startdate))) 
       = CONVERT(date, c.orig_enddate) 
      THEN c.orig_enddate 
      ELSE DATEADD(SECOND,-1,CONVERT(datetime,DATEADD(day,c.iteration+1,CONVERT(date,c.orig_startdate)))) 
     END as enddate, 
     c.iteration+1 as iteration 
    FROM cte as c 
    WHERE DATEADD(day,c.iteration,CONVERT(date,c.orig_startdate)) <= CONVERT(date, c.orig_enddate) 
) 
SELECT data.id, data.startdate, data.enddate, data.currentDate, data.minutesCurrentDay 
FROM (
    SELECT c.id, c.orig_startdate as startdate, c.orig_enddate as enddate, 
     CONVERT(date,c.startdate) as currentDate, 
     DATEDIFF(minute,c.startdate,c.enddate)+1 as minutesCurrentDay 
     --1 due to the timeshifting to get the days in line 
    FROM cte as c 
    UNION ALL 
    SELECT t.id, t.startdate, t.enddate, CONVERT(date, t.startdate) as currentDate, 
     DATEDIFF(minute,t.startdate, t.enddate) as minutesCurrentDay 
    FROM #timing as t 
    WHERE CONVERT(date,t.startdate) = CONVERT(date,t.enddate) 
) as data 
ORDER BY data.id, data.currentDate 

-- Cleanup 
DROP TABLE #timing 

我已經包含演示代碼和演示表結構。重點在於startdateenddate列。您需要將其調整爲您所需的表格結構。但是,如果沒有邏輯的話,那不會很難添加幾列。 :-)

這裏是演示輸入:

id   startdate    enddate 
----------- ----------------------- ----------------------- 
1   2015-06-19 12:55:32.313 2015-06-20 13:05:32.313 
2   2015-06-20 11:45:32.313 2015-06-20 12:55:32.313 
3   2015-06-17 12:55:32.313 2015-06-20 12:55:32.313 

這是查詢的結果:

id   startdate    enddate     currentDate minutesCurrentDay 
----------- ----------------------- ----------------------- ----------- ----------------- 
1   2015-06-19 13:03:35.887 2015-06-20 13:13:35.887 2015-06-19 657 
1   2015-06-19 13:03:35.887 2015-06-20 13:13:35.887 2015-06-20 794 
2   2015-06-20 11:53:35.887 2015-06-20 13:03:35.887 2015-06-20 70 
3   2015-06-17 13:03:35.887 2015-06-20 13:03:35.887 2015-06-17 657 
3   2015-06-17 13:03:35.887 2015-06-20 13:03:35.887 2015-06-18 1440 
3   2015-06-17 13:03:35.887 2015-06-20 13:03:35.887 2015-06-19 1440 
3   2015-06-17 13:03:35.887 2015-06-20 13:03:35.887 2015-06-20 784 

順便說一句。子查詢周圍的結果中的ORDER BY不需要,如果你不會在有序狀態的結果。

+0

我希望它是直截了當的,你看我想每天獲得狀態持續時間,並且日期可以超過兩天它會拋出數字。 CalculateReportDuration是已經使用DATEDIFF()的存儲函數,我將編輯我的文章併爲其添加代碼。 – user515031

+0

啊好的。你想得到以下? 12點開始第一天8點結束。你想要2個結果。一天計算12小時,一天計算8小時。對? – Ionic

+0

是的,這就是我以後 – user515031

0

所以像這樣?

declare @start date, @end date 
set @start = '20150616' 
set @end = dateadd(day, 1, @start) 

SELECT 
    Name, State, 
    datediff(second, 
     case when StartDate < @start then @start else StartDate end, 
     case when EndDate > @end then @end else EndDate end)/60.0 as Duration 
FROM 
    [emc].[dbo].[TMB_MachineStateReport] 
WHERE 
    EndDate > @start 
    StartDate < @end 

這需要一切其中該範圍具有給定天重疊,並且計算時間無論是從該行的開始/結束或開始一天的/結束,這取決於哪一個是對問題的日子。

沒有測試過,所以希望它有效。

+0

它的工作比我的簡潔得多:-)所以沒有使用變量?我曾希望創建一個視圖,以便我可以在Excel中輕鬆創建一些圖表。另外你會如何顯示每天的結果,它只是一個while循環增量@start? 感謝您的幫助 – user515031

+0

您需要一個日期範圍並計算每天的金額?你只需要一個日期表(=每天有一行的表),然後加入在這個查詢中使用。 @start =表格中的日期,@ @ end =表格中的日期+ 1 –

+0

好的,再感謝一個問題,然後我將其標記爲已回答。如何建議在Excel電子表格中顯示此查詢的結果,因爲據我所知,您不能在查詢中使用excel中的變量? – user515031

相關問題