我想计算用户在网站上花费的总时间。有3种情况。
存在用户登录时间和注销时间的记录。
- >总时间应为登录和退出之间的时差总和。
有用户登录时间的记录,但没有退出时间。
- >总时间应标记为-1。
用户多次登录,只有一次退出时间。
- >总时间应该是最早登录时间和退出时间之间的时差总和。
我的表
CREATE TABLE #my_table
(
id BIGINT IDENTITY PRIMARY KEY
,userID INT
,login_time DATETIME
,logout_time DATETIME
);
INSERT INTO #my_table
SELECT 222222, '2016-05-19 01:06:00.000', '2016-05-19 01:10:00.000'
UNION ALL SELECT 222222, '2016-05-19 01:12:00.000', '2016-05-19 01:20:00.000'
UNION ALL SELECT 333333, '2016-05-24 14:44:00.000', '2016-05-24 14:47:00.000'
UNION ALL SELECT 333333, '2016-05-24 14:59:00.000', NULL
UNION ALL SELECT 444444, '2016-05-24 14:48:00.000', '2016-05-24 14:49:00.000'
UNION ALL SELECT 444444, '2016-05-24 14:50:00.000', NULL
UNION ALL SELECT 444444, '2016-05-24 14:51:00.000', NULL
UNION ALL SELECT 444444, '2016-05-24 14:53:00.000', '2016-05-24 14:59:00.000'
预期结果
对于大多数情况,数据库中捕获的记录将是案例1,但有时也会捕获案例2和案例3。我需要一个脚本来计算所有案例的总登录时间。
我该如何查询?
答案 0 :(得分:1)
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = MsgBox("Please confirm cancellation", vbOKCancel + vbQuestion) = vbCancel
End Sub
答案 1 :(得分:1)
下面的查询多次使用ROW_NUMBER
函数来选择所需的行,LEAD
函数在logout_time
为NULL时“向前看”。自SQL Server 2012以来,LEAD
可用。
逐步运行查询,CTE-by-CTE并检查中间结果以了解其工作原理。
CTE_Groups
是一个经典gaps-and-islands
查询,用于在logout_time
中标记连续NULL的行。
CTE_RN
以这种方式为行分配数字,logout_time
中的连续NULL获得连续数字。此结果在CTE_Fixed
中过滤,以便每组NULL只获得第一行。如果logout_time
为NULL,则LEAD
函数用于从下一行中选择一个值以生成fixed_logout_time
。
具有NULL logout_time
的行和具有非NULL logout_time
的下一行将在CTE_Fixed
中一起列出。我们需要从这些对中选择一行。相同方法 - 在ROW_NUMBER
中使用CTE_FixedRN
并选择CTE_Sum
中的第一行。
然后我们可以在几分钟内计算Duration
,并将总和按userID
分组。
如果没有非NULL logout_time
,DATEDIFF
将返回NULL,将替换为一些大的负数。在最终SELECT
中,否定Duration
将替换为-1
,表示上一个时间间隔仍处于打开状态。
WITH
CTE_Groups
AS
(
SELECT
userID
,login_time
,logout_time
,ROW_NUMBER()
OVER(PARTITION BY userID ORDER BY login_time)
- ROW_NUMBER()
OVER(PARTITION BY userID, logout_time ORDER BY login_time) AS GroupNumber
FROM #my_table
)
,CTE_RN
AS
(
SELECT
userID
,login_time
,logout_time
,ROW_NUMBER()
OVER(PARTITION BY userID, GroupNumber ORDER BY login_time) AS rn
FROM CTE_Groups
)
,CTE_Fixed
AS
(
SELECT
userID
,login_time
,ISNULL(logout_time, LEAD(logout_time)
OVER(PARTITION BY userID ORDER BY login_time)) AS fixed_logout_time
FROM CTE_RN
WHERE rn = 1
)
,CTE_FixedRN
AS
(
SELECT
userID
,login_time
,fixed_logout_time
,ROW_NUMBER()
OVER(PARTITION BY userID, fixed_logout_time ORDER BY login_time) AS rn
FROM CTE_Fixed
)
,CTE_Sum
AS
(
SELECT
userID
,SUM(ISNULL(
DATEDIFF(minute, login_time, fixed_logout_time),
-1000000)) AS Duration
FROM CTE_FixedRN
WHERE rn = 1
GROUP BY userID
)
SELECT
userID
,CASE WHEN Duration < 0 THEN -1 ELSE Duration END AS Duration
FROM CTE_Sum
ORDER BY userID;
<强>结果强>
+--------+----------+
| userID | Duration |
+--------+----------+
| 222222 | 12 |
| 333333 | -1 |
| 444444 | 10 |
+--------+----------+