sql - 处理 SQL 日期时间中缺少的登录/注销值
问题描述
我的 Sql 查询:
CREATE TABLE TimeLog (
[User] NVARCHAR(6),
[Event] NVARCHAR(3),
[Time] DATETIME
);
INSERT INTO TimeLog VALUES
(N'Jibran',N'IN','2015-04-15 00:31:00'),
(N'Jibran',N'IN','2015-04-16 20:10:00'),
(N'Jibran',N'IN','2015-04-21 14:59:00'),
(N'Jibran',N'OUT','2015-04-22 01:01:00'),
(N'Jibran',N'IN','2015-04-22 10:46:00'),
(N'Jibran',N'OUT','2015-04-23 00:58:00'),
(N'Jibran',N'IN','2015-04-23 14:50:00'),
(N'Jibran',N'OUT','2015-04-24 01:37:00'),
(N'Jibran',N'OUT','2015-04-25 01:01:00'),
(N'Jibran',N'OUT','2015-04-27 00:57:00'),
(N'Jibran',N'IN','2015-04-17 10:32:00'),
(N'Jibran',N'IN','2015-04-29 15:03:00'),
(N'Jibran',N'OUT','2015-05-01 00:44:00'),
(N'Jibran',N'OUT','2015-05-02 01:19:00'),
(N'Jibran',N'IN','2015-05-02 15:08:00'),
(N'Jibran',N'OUT','2015-05-03 01:08:00'),
(N'Jibran',N'IN','2015-05-03 15:06:00'),
(N'Jibran',N'OUT','2015-05-04 01:01:00'),
(N'Jibran',N'IN','2015-05-04 15:11:00'),
(N'Jibran',N'OUT','2015-05-05 01:08:00');
SELECT TOP (30) UserName, EventName, EventTime
From AttendanceEvents
Where UserName = 'Jibran'
结果是 :
有没有办法处理每个没有 OUT 日期时间值的 IN 值的缺失值?
但是中途没看懂。
如何获得 Datetime 的平均值以将其用于缺失值?
预期输出将具有每个 IN 的 OUT 值。
谢谢。
解决方案
我想出了一个将缺失的行添加到表中的解决方案——对于缺失的in
行和缺失的out
行。
我所做的与您所要求的不同的一件事是缺失的行在其源行中完成了 8 小时的一天。
请注意,每次只能由一个用户使用。
所以这里是如何:
首先,我创建了一个公用表表达式,其中包含表中属于特定用户的所有行。在那个 cte 中,我使用lag
andlead
来获取下一个事件、上一个事件和下一个事件时间,以及一个 row_number 列。
然后,我使用了基于该 cte 的所有三个查询的联合——一个用于原始行,一个用于带有in
事件的新行,一个用于带有事件的新行out
。
该脚本基于您的示例数据,您可以在 rextester 上查看在线演示。
DECLARE @User nvarchar(6) = N'Jibran';
WITH CTE AS
(
SELECT [User],
[Event],
[Time],
ROW_NUMBER() OVER(ORDER BY [Time]) + 0.0 As rn,
LAG([Event]) OVER(ORDER BY [Time]) As PrevEvent,
LEAD([Event]) OVER(ORDER BY [Time]) As NextEvent,
LEAD([Time]) OVER(ORDER BY [Time]) As NextEventTime
FROM TimeLog
WHERE [User] = @User
)
SELECT [User],
'OUT' As [Event],
DATEADD(HOUR, 8, [Time]) As [Time],
rn + 0.5 As rn
FROM CTE
WHERE NextEvent = [Event]
AND [Event] = 'IN'
UNION ALL
SELECT [User],
'IN' As [Event],
DATEADD(HOUR, -8, [NextEventTime]) As [Time],
rn - 0.3 As rn
FROM CTE
WHERE PrevEvent = [Event]
AND [Event] = 'OUT'
UNION ALL
SELECT [User],
[Event],
[Time],
rn
FROM CTE
ORDER BY rn
结果:
User Event Time rn
Jibran IN 15.04.2015 00:31:00 1,0
Jibran OUT 15.04.2015 08:31:00 1,5
Jibran IN 16.04.2015 20:10:00 2,0
Jibran OUT 17.04.2015 04:10:00 2,5
Jibran IN 17.04.2015 10:32:00 3,0
Jibran OUT 17.04.2015 18:32:00 3,5
Jibran IN 21.04.2015 14:59:00 4,0
Jibran OUT 22.04.2015 01:01:00 5,0
Jibran IN 22.04.2015 10:46:00 6,0
Jibran OUT 23.04.2015 00:58:00 7,0
Jibran IN 23.04.2015 14:50:00 8,0
Jibran OUT 24.04.2015 01:37:00 9,0
Jibran IN 26.04.2015 16:57:00 9,7
Jibran OUT 25.04.2015 01:01:00 10,0
Jibran IN 29.04.2015 07:03:00 10,7
Jibran OUT 27.04.2015 00:57:00 11,0
Jibran IN 29.04.2015 15:03:00 12,0
Jibran OUT 01.05.2015 00:44:00 13,0
Jibran IN 02.05.2015 07:08:00 13,7
Jibran OUT 02.05.2015 01:19:00 14,0
Jibran IN 02.05.2015 15:08:00 15,0
Jibran OUT 03.05.2015 01:08:00 16,0
Jibran IN 03.05.2015 15:06:00 17,0
Jibran OUT 04.05.2015 01:01:00 18,0
Jibran IN 04.05.2015 15:11:00 19,0
Jibran OUT 05.05.2015 01:08:00 20,0
旁注:您可以根据 rn.all 查询的哪个部分添加了哪一行。
更新
按照我们在问题评论中的对话 - 为了获得不同列中的来龙去脉,我将 union all 查询包装在另一个 cte 中,并在此之上再放一个 cte 以获得 bigint 行号。然后它只是一个带有扭曲的条件聚合问题 - 使用交叉应用将偶数和奇数行号配对成组。
这是完整的脚本 - 当然,还有一个在线演示:
DECLARE @User nvarchar(6) = N'Jibran';
WITH CTE AS
(
SELECT [User],
[Event],
[Time],
ROW_NUMBER() OVER(ORDER BY [Time]) + 0.0 As rn,
LAG([Event]) OVER(ORDER BY [Time]) As PrevEvent,
LEAD([Event]) OVER(ORDER BY [Time]) As NextEvent,
LEAD([Time]) OVER(ORDER BY [Time]) As NextEventTime
FROM TimeLog
WHERE [User] = @User
), CTERows AS
(
-- Added out rows
SELECT [User],
'OUT' As [Event],
DATEADD(HOUR, 8, [Time]) As [Time],
rn + 0.5 As rn
FROM CTE
WHERE NextEvent = [Event]
AND [Event] = 'IN'
UNION ALL
-- Added in rows
SELECT [User],
'IN' As [Event],
DATEADD(HOUR, -8, [NextEventTime]) As [Time],
rn - 0.3 As rn
FROM CTE
WHERE PrevEvent = [Event]
AND [Event] = 'OUT'
UNION ALL
-- Existing rows
SELECT [User],
[Event],
[Time],
rn
FROM CTE
), CTEIntNumberedRows AS
(
SELECT [User],
[Event],
[Time],
ROW_NUMBER() OVER (ORDER BY rn) As rn
FROM CteRows
)
SELECT [User],
MAX(CASE WHEN [Event] = 'IN' THEN [Time] END) As 'IN',
MAX(CASE WHEN [Event] = 'OUT' THEN [Time] END) As 'OUT',
Pairs
FROM CTEIntNumberedRows
CROSS APPLY
(
SELECT CASE WHEN rn % 2 = 0 THEN rn-1 ELSE rn END As Pairs
) x
GROUP BY [User], Pairs
ORDER BY Pairs
推荐阅读
- blockchain - 交易发生时如何将特定数量的代币转移给 Solidity 中的每个持有者?
- c# - 使用高分辨率计时器在 WPF 中工作时出现异常
- reactjs - Typescript 滚动窗口函数类型
- ios - 为什么将 .navigationBarBackButtonHidden(true) 添加到我的 ContentView 会破坏核心 NavigationView 动画以切换视图?这是一个错误吗?
- r - ggplot:条形顶部的百分比,但依靠 y-aes
- oracle - PLSQL / DBMS_Out - 如何返回特定值?
- javascript - 在 forEach 循环下过滤数组
- angular - 错误:资源 URL 上下文中使用了不安全的值(请参阅 https://g.co/ng/security#xss)
- xmlhttprequest - 页面加载后禁用内容安全策略
- android - 初始化后如何保存变量的值