我正在尝试计算自助服务终端机器上事件之间的时差(以秒为单位)。每当一个人开始使用屏幕时,它就会创建一个VisitID。在该访问中,创建了一系列计算机事件,用于确定屏幕的开始和屏幕的结束我已为每个屏幕确定了每个事件。根据用户的选择,他们可能会或可能不会通过每个事件或屏幕。我的数据如下:
VisitID ScreenTime EventName
1 13:24:08 WelcomeScreen_Begin
1 13:24:15 Welcome_End
1 13:24:15 NameScreenInit_Start
1 13:24:32 Name_Screen_Terminate
1 13:24:33 CompanyScreen_Enter
1 13:24:45 Company_Lookup
1 13:24:45 Signoff_Now
1 13:24:52 SignOutEnd
2 13:45:02 WelcomeScreen_Begin
2 13:45:15 Welcome_End
2 13:45:15 NameScreenInit_Start
2 13:45:40 Name_Screen_Terminate
2 13:45:40 Signoff_Now
2 13:45:58 SignOutEnd
我希望我的结果看起来像这样:
VisitID WelcomeScreen NameScreen CompanyScreen SignoffScreen
1 00:00:7 00:00:17 00:00:12 00:00:07
2 00:00:13 00:00:25 NULL 00:00:18
最终,我想计算在每个屏幕上花费的平均时间:
WelcomeScreenAVG NameScreenAVG CompanyScreenAVG SignoffScreenAVG
00:00:10 00:00:21 00:00:12 00:00:13
我已经能够使用下标来获取DATEDIFF子句中的每个时间戳,但只有在WHERE子句中包含VisitID时它才有效。我有成千上万的条目,所以不是这样做的。我好久以来一直绞尽脑汁。有没有人有解决方案,或者至少知道我应该做什么呢?提前谢谢!
当可用于表示一个屏幕的开头的唯一事件是结束先前屏幕的同一事件时,会发生一些事件。例如:
VisitID ScreenTime EventName
34 08:34:36 Delivery_summaryConfirm
34 08:34:47 Seal_questionsBegin
34 08:35:17 EndSeal_Inquiry
^^这是2个屏幕^^在上面的示例中,虽然Seal_questionsBegin是SealInquiry屏幕的开头,但它是唯一能够表示DeliverySummary屏幕结束的事件。这是因为DeliverySummary屏幕后面总是跟着SealInquiry屏幕。
答案 0 :(得分:0)
将数据集拆分为"开始"和"结束",然后通过以下方式进行简单的连接和组:
SELECT
Begins.ScreenName,
AVG(DateDiff(second, Begins.ScreenTime, Ends.ScreenTime)) AS TimeSpentSeconds
FROM (
SELECT
VisitID,
LEFT(EventName, LEN(EventName)-5) AS ScreenName,
ScreenTime
FROM MyTable WHERE EventName LIKE '%Begin'
) AS Begins
INNER JOIN (
SELECT
VisitID,
LEFT(EventName, LEN(EventName)-3) AS ScreenName,
ScreenTime
FROM MyTable WHERE EventName LIKE '%End'
) AS Ends
ON Begins.VisitID = Ends.VisitID AND Begins.ScreenName = Ends.ScreenName
GROUP BY Begins.ScreenName
以行方式返回数据:
ScreenName TimeSpentSeconds
---------- ----------------
WelcomeScreen 10
NameScreen 21
CompanyScreen 12
SignoffScreen 13
答案 1 :(得分:0)
更新
如果您有每个屏幕的固定事件列表,您可以执行以下操作。我认为它看起来更容易阅读,并且比其他帖子更简单......但那就是我。
With tblUserTimes as (
Select VisitId,
DateDiff(second,
Max(Case When EventName = 'WelcomeScreen_Begin' Then ScreenTime End),
Max(Case When EventName = 'Welcome_End' Then ScreenTime End)) as WelcomeScreen,
DateDiff(second,
Max(Case When EventName = 'NameScreenInit_Start' Then ScreenTime End),
Max(Case When EventName = 'Name_Screen_Terminate' Then ScreenTime End)) as NameScreen,
DateDiff(second,
Max(Case When EventName = 'CompanyScreen_Enter' Then ScreenTime End),
Max(Case When EventName = 'Company_Lookup' Then ScreenTime End)) as CompanyScreen,
DateDiff(second,
Max(Case When EventName = 'Signoff_Now' Then ScreenTime End),
Max(Case When EventName = 'SignOutEnd' Then ScreenTime End)) as SignoffScreen
from Visits
Group By VisitId)
Select AVG(WelcomeScreen) as WelcomeScreenAvg,
AVG(NameScreen) as NameScreenAvg,
AVG(CompanyScreen) as CompanyScreenAvg,
AVG(SignoffScreen) as SignoffScreenAvg
from tblUserTimes
请参阅this SQL Fiddle,例如使用数据透视。
答案 2 :(得分:0)
首先想到你需要的是规范化事件名称,查询要注意这一点,你是否可以规范化数据或者至少在你的数据库中创建一个翻译表
修改强>
这些事件比我最初的想法更多,翻译应该被创建为一个完整的表格。
我们可以利用Translate
表,添加IsBegin和IsEnd位字段并将NormName字段映射到屏幕名称,除了字典外,还会生成Times {{1}中的简化逻辑}}
CTE
如果事件名称既是事件的结尾又是新事件的开始,则应该插入两次,如' Seal_questionsBegin'在示例中
CREATE TABLE NormalizeEvents (
RealName VARCHAR(50)
, NormName VARCHAR(50)
, IsBegin BIT
, IsEnd BIT
)
INSERT INTO NormalizeEvents (RealName, NormName, IsBegin, IsEnd)
VALUES ('WelcomeScreen_Begin', 'WelcomeScreen', 1, 0)
, ('Welcome_End', 'WelcomeScreen', 0, 1)
, ('NameScreenInit_Start', 'NameScreen', 1, 0)
, ('Name_Screen_Terminate', 'NameScreen', 0, 1)
, ('CompanyScreen_Enter', 'CompanyScreen', 1, 0)
, ('Company_Lookup', 'CompanyScreen', 0, 1)
, ('Signoff_Now', 'SignoffScreen', 1, 0)
, ('SignOutEnd', 'SignoffScreen', 0, 1)
, ('Delivery_summaryConfirm', 'DeliverySummary', 1, 0)
, ('Seal_questionsBegin', 'DeliverySummary', 0, 1)
, ('Seal_questionsBegin', 'SealQuestions', 1, 0)
, ('EndSeal_Inquiry', 'SealQuestions', 0, 1)
要获取每个屏幕的全局平均值,只需删除WITH Times AS (
SELECT VisitID, EventName = t.NormName
, ScreenTimeBegin = Max(CASE t.IsBegin
WHEN 1 THEN ScreenTime
ELSE NULL
END)
, ScreenTimeEnd = Max(CASE t.IsEnd
WHEN 1 THEN ScreenTime
ELSE NULL
END)
FROM Events e
INNER JOIN NormalizeEvents t ON e.EventName = t.RealName
GROUP BY VisitID, NormName
)
SELECT VisitID
, [WelcomeScreen] = CAST(DATEADD(ss, WelcomeScreen, '1900-01-01') as Time)
, [CompanyScreen] = CAST(DATEADD(ss, CompanyScreen, '1900-01-01') as Time)
, [NameScreen] = CAST(DATEADD(ss, NameScreen, '1900-01-01') as Time)
, [SignoffScreen] = CAST(DATEADD(ss, SignoffScreen, '1900-01-01') as Time)
, [DeliverySummary]=CAST(DATEADD(ss, DeliverySummary, '1900-01-01') as Time)
, [SealQuestions] = CAST(DATEADD(ss, SealQuestions, '1900-01-01') as Time)
FROM (SELECT VisitID, EventName
, Duration = DateDiff(ss, ScreenTimeBegin, ScreenTimeEnd)
FROM Times) SOURCE
PIVOT (AVG(Duration) FOR EventName IN
([WelcomeScreen], [CompanyScreen], [NameScreen], [SignoffScreen]
, [DeliverySummary], [SealQuestions])
) pvt
的来源中的VisitID
字段和主查询。
PIVOT
SQLFiddle demo(数据过时)。
由于我假设SQLServer 2012或更高版本的问题未指定SQLServer版本。