+---------+-----------+----------+---------+
| FileID | EventDate | UserName | EventID |
+---------+-----------+----------+---------+
| 1000001 | DateTime | User1 | 1 |
| 1000001 | DateTime | User1 | 3 |
| 1000001 | DateTime | User1 | 3 |
| 1000001 | DateTime | User1 | 1 |
| 1000001 | DateTime | User1 | 3 |
| 1000001 | DateTime | User1 | 3 |
| 1000001 | DateTime | User1 | 3 |
| 1000002 | DateTime | User1 | 1 |
| 1000002 | DateTime | User1 | 3 |
+---------+-----------+----------+---------+
我有一个表格,其中的事件数据与上面的例子类似。每个事件都有一个FileID,EventID,UserName和一个Datetime。事件ID 1是打开文件的用户,事件ID 3是保存事件。事件ID 3的最后一行表示文件关闭,因为每个文件都在关闭时保存。我需要能够将用户在文件中的总时间(最终事件3的时间 - 事件1的时间)相加,但如果用户多次输入文件,则无法确定如何执行此操作。有任何想法吗?
答案 0 :(得分:1)
create table events (FileID int, EventDate datetime, UserName varchar(10), EventID int); insert into events values (1000001, '20180101 10:00:00', 'User1', 1 ), (1000001, '20180101 10:30:00', 'User1', 3 ), (1000001, '20180101 10:45:00', 'User1', 3 ), (1000001, '20180102 11:00:00', 'User1', 1 ), (1000001, '20180102 11:30:00', 'User1', 3 ), (1000001, '20180102 11:45:00', 'User1', 3 ), (1000001, '20180102 12:00:00', 'User1', 3 ), (1000002, '20180101 05:00:00', 'User1', 1 ), (1000002, '20180101 05:45:00', 'User1', 3 ); GO
9 rows affected
select FileID, sum(minutes) totalTime from ( select FileID, grp, datediff(minute, min(EventDate), max(EventDate)) minutes from ( select FileID, EventDate, UserName, EventID, sum(iif(EventID = 1,1,0)) over (order by FileID, EventDate) grp from events ) t group by FileId, grp ) t2 group by FileID GO
FileID | totalTime ------: | --------: 1000001 | 105 1000002 | 45
dbfiddle here
答案 1 :(得分:0)
只是做一些奇特的连接:
select fileID,userName,eventDate 'startDate',min(t2.eventDate) 'nextStart'
into #temp1
from logTable t1
left join logTable t2 on t1.fileID=t2.fileID and t1.userName=t2.userName and t2.eventID=1 and t1.eventDate<t2.eventDate
where t1.eventID=1
group by fileID,eventDate,userName
select fileID,userName,startDate,max(t2.eventDate) 'endDate'
from #temp1 t1
left join logTable t2 on t1.fileID=t2.fileID and t1.userName=t2.userName and t2.eventID=3 and t2.eventDate>t1.startDate and t2.eventDate<t1.nextStart
您无法获得所花费的时间,直到用户再次打开相同的文件,因为您没有最近的时间。但您可以将第二个连接修改为...(t2.eventDate<t1.nextStart or t1.nextStart is null)
这将获得到最后一个保存点的开始时间
答案 2 :(得分:0)
再次使用LEAD()
和LAG()
,这是SQL2012 +。
MS SQL Server 2017架构设置:
CREATE TABLE t ( FileID int, EventDate datetime, UserName varchar(20), EventID int ) ;
INSERT INTO t (FileID, EventDate, UserName, EventID)
VALUES
(1000001,'2018-01-01T00:00:00.000','User1',1) /* OPEN 1 */
, (1000001,'2018-01-01T00:01:15.000','User1',3) /* SAVE 1 */
, (1000001,'2018-01-01T00:01:30.000','User1',3) /* CLOSE 1 */ /* 1 = 0:01:30 */
, (1000001,'2018-01-01T00:02:00.000','User1',1) /* OPEN 2 */
, (1000001,'2018-01-01T00:02:15.000','User1',3) /* SAVE 2 */
, (1000001,'2018-01-01T00:02:30.000','User1',3) /* SAVE 2 */
, (1000001,'2018-01-01T00:03:00.000','User1',3) /* SAVE 2 */
, (1000002,'2018-02-01T00:00:00.500','User1',1) /* OPEN 1 */
, (1000001,'2018-01-01T00:10:00.000','User1',3) /* CLOSE 2 */ /* 2 = 0:08:00 */
, (1000002,'2018-02-01T00:01:00.000','User1',3) /* SAVE 1 */
, (1000002,'2018-02-01T00:02:00.000','User1',3) /* CLOSE 1 */ /* 1 = 0:01:59.500 */
, (1000088,'2018-02-10T00:00:00.000','NoCloseUser',1) /* OPEN - NOT CLOSED */
, (1000099,'2018-02-10T00:00:00.000','NoOpenUser',3) /* CLOSED - NOT OPENED */
;
我添加了几个糟糕的记录。一个没有关闭日期,但仍会显示在结果中。这纯粹是坏事,没有记录开放日期,但不会弄乱数据。可以在查询中过滤Opened-But-Not-Closed记录。
<强>查询强>:
; WITH closes AS (
SELECT *
FROM (
SELECT t.FileID, t.UserName, t.EventDate, t.EventID
, LEAD(t.EventID) OVER (PARTITION BY t.FileID, t.UserName ORDER BY t.EventDate) AS leadEvent
FROM t
) s1
WHERE s1.EventID = 3 AND COALESCE(s1.leadEvent,1) = 1
)
, opens AS (
SELECT t.FileID, t.UserName, t.EventDate
, LEAD(t.EventDate) OVER ( PARTITION BY t.FileID, t.UserName ORDER BY t.EventDate ) AS nextOpen
FROM t
WHERE t.EventID = 1
)
SELECT s2.FileID, s2.UserName, SUM(minOpen) AS totalMinOpen
FROM (
SELECT o.FileID, o.UserName
, o.EventDate as openDate
, o.nextOpen
, c.EventDate closeDate
, c.leadEvent
, DATEDIFF(second, o.EventDate,COALESCE(c.EventDate,getDATE()))/60.0 AS minOpen
FROM opens o
LEFT OUTER JOIN closes c ON o.FileID = c.FileID
AND o.UserName = c.UserName
AND o.EventDate <= COALESCE(c.EventDate,getDATE())
AND ( c.leadEvent IS NOT NULL OR o.nextOpen IS NULL )
) s2
GROUP BY s2.FileID, s2.UserName
<强> Results 强>:
| FileID | UserName | totalMinOpen |
|---------|-------------|--------------|
| 1000001 | User1 | 9.5 |
| 1000002 | User1 | 2 |
| 1000088 | NoCloseUser | 28694 |
我使用LEAD()
和LAG()
来确定文件关闭位置然后再次打开之间的区域。我使用CTE来存储用于确定打开和关闭的各个查询。我将它差异化为秒,然后除以60.0得到分钟的十进制表示。我确信这个查询可以稍微优化一下。