计算具有大型数据集的不同状态的机器所花费的时间的有效方法

时间:2016-06-09 13:07:04

标签: sql sql-server qlikview

我无法找到解决此问题的好方法。我有一个如下所示的数据集:

MACHINE     DATETIME                 CODE  
C54118PC1   2016-04-01 00:00:01.000  10
C54118PC1   2016-04-01 00:01:12.000  4
C54118PC1   2016-04-01 00:01:36.000  10
C54118PC1   2016-04-01 00:01:50.000  4
C54123PC1   2016-04-01 00:00:02.000  0
C54123PC1   2016-04-01 01:00:02.000  0

最终,我希望在Qlikview文档中将其显示为饼图,显示机器在每个州(代码)中花费的时间。

为了做到这一点,我想我需要以这种格式获取数据:

MACHINE     DATE       CODE DURATION
Machine1    07/06/2016  2   07:30:14
Machine1    07/06/2016  5   02:45:10
Machine2    07/06/2016  0   12:37:05
Machine2    07/06/2016  5   04:04:59
Machine1    08/06/2016  2   02:57:13
Machine1    08/06/2016  4   04:12:05
Machine1    08/06/2016  5   03:07:12
Machine3    08/06/2016  8   02:49:23

对于每台机器,每台机器的每行代码为1行,包含当天的总持续时间和代码。

另一个考虑因素是这是一个大型数据集 - 目前至少有200万行,随着更多机器的添加和更多时间的推移,这可能会很快增长。

所以,基本上我需要一种非常有效的方法来计算在不同状态(代码)中花费的时间,按机器和日期。我认为这最好在SQL中完成,但是我也可以在Qlikview中做到这一点,如果这样做更有效率。有人可以帮忙吗?

提前谢谢!




编辑:对不起,我忘了解释日志记录是如何工作的!我们有一堆机器在白天在各种状态之间交替(例如打印,空闲,清洁)。每次它们改变状态(例如从打印到空闲)时,它们都会记录时间戳以及它们的新状态。

(它们还会定期记录时间戳及其当前状态,即使它们实际上没有改变状态。)

持续时间计算为两个连续时间戳之间的时差。

3 个答案:

答案 0 :(得分:0)

UNTESTED: LEAD()一个分析(窗口函数),可以让你查看给定数据分区的下一个有序行值,看起来它会起作用......

所以在这种情况下:我们想要给定机器的下一行的日期时间,而不管状态......如下:

SELECT MACHINE
     , FORMAT(DATETIME, 'DD/MM/YYYY')
     , CODE
     , SUM(Lead(DateTIme) over (partition by Machine order by dateTime asc) - datetime) AS DURATION, 
FROM TABLENAME
GROUP BY MACHINE, CODE, FORMAT(DATETIME, 'DD/MM/YYYY')

我不确定这里的数据数学是为了获得持续时间。

答案 1 :(得分:0)

试试这个

Declare @Table table (machine varchar(25),DateTime datetime,Code int)
Insert into @Table (Machine,DateTime,Code) values 
('Machine1','2016-04-01 00:00:01.000',10),
('Machine1','2016-04-01 00:01:12.000',4),
('Machine1','2016-04-01 00:01:36.000',10),
('Machine1','2016-04-01 00:01:50.000',4),
('Machine2','2016-04-01 00:00:02.000',0),
('Machine2','2016-04-01 01:00:02.000',0),
('Machine1','2016-04-02 00:00:01.000',10),
('Machine1','2016-04-02 00:01:12.000',4),
('Machine1','2016-04-02 00:01:36.000',10),
('Machine1','2016-04-02 00:01:50.000',4),
('Machine2','2016-04-02 00:00:02.000',0),
('Machine2','2016-04-02 01:00:02.000',0)


IF OBJECT_ID('tempdb.dbo.#Temp1', 'U') IS NOT NULL
    DROP TABLE #Temp1; 

-- Generate Date Range
Select Distinct DateR1=cast(DateTime as Date),DateR2=DateAdd(DD,1,cast(DateTime as Date)) into #Temp1 from @Table
Create Index idx on #Temp1 (DateR1,DateR2)

;with cteBase as (
        Select *
             ,MSDate1 = DateTime
             ,MSDate2 = Lead(DateTime,1,DateAdd(DD,1,cast(DateTime as Date)))  over (Partition by Machine Order by Machine,DateTime) 
         From @Table
      )
Select Machine
      ,Date = DateR1
      ,Code
      ,Duration = CONVERT(varchar, DATEADD(SS, sum(DateDiff(SS,case when MSDate1<=DateR1 then DateR1 else MSDate1 end,case when MSDate2>DateR2 then DateR2 else MSDate2 end)), 0), 114)
 From #Temp1 A
 Join cteBase B on (MSDate1 between DateR1 and DateR2 or MSDate2 between DateR1 and DateR2)
 Group By Machine
      ,DateR1
      ,Code

返回

Machine         Date        Code    Duration
Machine1        2016-04-01  4       23:58:34:000
Machine1        2016-04-01  10      00:01:25:000
Machine1        2016-04-02  4       23:58:35:000
Machine1        2016-04-02  10      00:01:25:000
Machine2        2016-04-01  0       23:59:58:000
Machine2        2016-04-02  0       00:00:00:000

答案 2 :(得分:0)

这可以在QV本身轻松实现(参见下面的脚本)。

关于数据大小。您可以在QV中实现Incremental Load并在重新加载应用时仅加载新记录,并仅在小集上执行转换,而不是在完整数据集上执行转换。

示例工作流程将:在每次重新加载时仅提取最后日期的记录,执行转换,从qvd加载先前转换的数据并将新结果连接到qvd。这是QV非常常见的方法(我每天使用它)。通常我更喜欢这种方法,因为我不会推动数据库进行QV的工作并避免与DBA发生冲突;)

如果你想我可以使用增量加载粘贴样本脚本(只需留下评论)

有关增量加载的更多详细信息:

示例脚本:

RawData:
Load
    MACHINE,  
//  DATETIME, // this is not needed anymore
    CODE,
    date(left(DATETIME, 10)) as Date, // extract the date
    mid(DATETIME, 12, 8) as Duration // extract the duration
; 
Load * Inline [
    MACHINE   , DATETIME                 , CODE  
    C54118PC1 , 2016-04-01 00:00:01.000  , 10
    C54118PC1 , 2016-04-01 00:01:12.000  , 4
    C54118PC1 , 2016-04-01 00:01:36.000  , 10
    C54118PC1 , 2016-04-01 00:01:50.000  , 4
    C54123PC1 , 2016-04-01 00:00:02.000  , 0
    C54123PC1 , 2016-04-01 01:00:02.000  , 0
];

Data:
Load
    interval(sum(Duration)) as TotalDuration, // sum the total duration and convert it to timestamp format
    MACHINE,  
    Date, 
    CODE
Resident
    RawData
Group By
    MACHINE,  
    Date, 
    CODE    
;   

Drop Table RawData; // this table is not needed anymore