2015-06-20 237 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

相关问题