怎样用sql查询一段时间内一天中的空闲时间和工作时间
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了怎样用sql查询一段时间内一天中的空闲时间和工作时间相关的知识,希望对你有一定的参考价值。
task_id task_name task_type submit_time file_numbers end_time
1 wan 1 2015-4-13 下午7:02:16 200 2015-4-13 下午7:30:53
3 wan 1 2015-4-13 下午7:57:26 301 2015-4-13 下午8:08:40
4 wan 1 2015-4-13 下午8:06:30 200 2015-4-13 下午8:09:04
查询13号,和14号的空闲时间
如果不考虑时间重叠的情况
select dt,sum(s) as 忙
,24*60*60 - sum(s) as 闲
from (
select to_char(submit_time,'yyyy/mm/dd') as dt
, end_time - submit_time as s
from table )
group by dt 参考技术A 把表结构及数据放出来,才能查啊。追问
task_id varchar
task_name varchar
task_type varchar
file_numbers varchar
submit_time timestamp
end_time timestamp
1 wan 1 2015-4-13 下午7:02:16 200 2015-4-13 下午7:30:53
2015-4-13 下午7:02:16 这之前
2015-4-13 下午7:30:53 之后,工作时间为28分钟左右,其他为空闲时间?
只能说说算法了:
先构建一个临时表,里面数据范围为当天0时1秒到23时50秒,都是数值,
再删除这个表里的值,范围为你每一天记录的时间段
这个时间段(开始及结束)时间,你同样转成数值 时*60*分*60+秒
剩下的就是空闲时间,这里,你要用个游标来循环数据,如果不是连续数,那就生成一段时间区域
额,没看懂,还有任务的时间有可能重叠
一天中每小时的 SQL 最大并发会话数
【中文标题】一天中每小时的 SQL 最大并发会话数【英文标题】:SQL max concurrent sessions per hour of day 【发布时间】:2014-12-30 10:52:38 【问题描述】:我在医疗保健呼叫中心工作。我可以访问我们核心系统的数据库,并且我想使用其中的数据来确定在可能超过 24 小时(例如 24/12/2014 - 26/)的给定时间段内每小时登录数据的员工数量12/2014)。
有一个userlog表,记录用户登录和注销的时间。
userlog 表示例
UserRef Date LogType SessionID
--------------------------------------- ----------------------- ------ -----------------------
96AD647C-D061-43F5-9F8D-FA6C74817E07 2002-10-17 14:11:25.763 LOGON 8D451569-0260-46BB-9B9E-F49B3E778161
96AD647C-D061-43F5-9F8D-FA6C74817E07 2002-10-17 18:11:32.547 LOGOFF 8D451569-0260-46BB-9B9E-F49B3E778161
60738820-5F72-4E20-A070-57E07C83B6DE 2002-10-17 14:53:31.153 LOGON C773894C-8B2D-4054-A550-3F04B4C5669F
60738820-5F72-4E20-A070-57E07C83B6DE 2002-10-17 22:55:25.607 LOGOFF C773894C-8B2D-4054-A550-3F04B4C5669F
90A55FDD-967E-4D99-96DF-96840CDB2CDF 2002-10-17 15:26:40.123 LOGON 1CE5F5A5-4E20-4D4A-BB67-EB0CB33976D7
96AD647C-D061-43F5-9F8D-FA6C74817E07 2002-10-17 15:51:28.590 LOGON 7EFDEE1C-15CF-4DE1-B59F-7AFC49B4BE73
90A55FDD-967E-4D99-96DF-96840CDB2CDF 2002-10-17 15:58:05.217 LOGOFF 1CE5F5A5-4E20-4D4A-BB67-EB0CB33976D7
96AD647C-D061-43F5-9F8D-FA6C74817E07 2002-10-17 15:58:31.013 LOGOFF 7EFDEE1C-15CF-4DE1-B59F-7AFC49B4BE73
90A55FDD-967E-4D99-96DF-96840CDB2CDF 2002-10-17 15:58:32.733 LOGON 03F56AB8-FED5-4CC7-8445-26BF55F58E60
90A55FDD-967E-4D99-96DF-96840CDB2CDF 2002-10-17 16:13:02.827 LOGOFF 03F56AB8-FED5-4CC7-8445-26BF55F58E60
期望的结果 (这不是为了反映上述示例数据):
Date Hour Number of users logged in
---- ---- -------------------------
01/12/2014 0 0
01/12/2014 1 0
01/12/2014 2 0
01/12/2014 3 0
01/12/2014 4 0
01/12/2014 5 1
01/12/2014 6 1
01/12/2014 7 1
01/12/2014 8 3
01/12/2014 9 7
01/12/2014 10 7
...
01/12/2014 23 0
明确一点:当没有用户登录时,我试图让小时数仍然显示为 0。
我想我正在寻找的是一天中每个小时的最大并发会话数,但我对 SQL 的技术或技能并不过分(不过会一点一点地变得更好!)所以我希望术语不会不要混淆!
我对此进行了谷歌搜索并发现了一些类似的场景,但对于 Oracle 和 MySQL,或者日志表以不同方式记录登录数据。我确信我会成功地将其他数据库查询代码“翻译”为 MS SQL,但我还没有做到这一点!
我正在使用:Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86)。
提前感谢您的帮助。
【问题讨论】:
你会在查询中传递日期/日期范围以指定我想要这个特定日期/日期范围的结果吗?另外,分享你的尝试。 @DeepakPawar 是的,我会的。除了将其放入包含会话 ID、登录日期、注销日期的列标题的表中外,我没有得到任何尝试。我不知道从那里去哪里。对不起:( 【参考方案1】:更新(v #4):
我在查询末尾添加了日期过滤器 - WHERE A.[Date] Between @X and @Y
- 在这种情况下,这不是最有效的方法,但我认为最简单,而且一开始就不容易出错:
SELECT
A.[Date],
A.[Hour],
SUM(CASE WHEN (B.[SessionID] IS NULL) THEN 0 ELSE 1 END) AS [Number_of_Sessions_Per_Hour]
FROM
(
SELECT DISTINCT
CONVERT(DATETIME,
LTRIM(RTRIM(CONVERT(NVARCHAR(10), YEAR(userlog.[Date]))))
+ '-' + RIGHT('0' + LTRIM(RTRIM(CONVERT(NVARCHAR(10), MONTH(userlog.[Date])))), 2)
+ '-' + RIGHT('0' + LTRIM(RTRIM(CONVERT(NVARCHAR(10), DAY(userlog.[Date])))), 2)
, 120) AS [Date],
hours_table.[Hour]
FROM
userlog,
(
SELECT 1 AS [Hour] UNION ALL SELECT 3 AS [Hour] UNION ALL SELECT 4 AS [Hour] UNION ALL SELECT 5 AS [Hour] UNION ALL SELECT 6 AS [Hour]
UNION ALL SELECT 7 AS [Hour] UNION ALL SELECT 7 AS [Hour] UNION ALL SELECT 8 AS [Hour] UNION ALL SELECT 9 AS [Hour] UNION ALL SELECT 10 AS [Hour]
UNION ALL SELECT 11 AS [Hour] UNION ALL SELECT 12 AS [Hour] UNION ALL SELECT 13 AS [Hour] UNION ALL SELECT 14 AS [Hour] UNION ALL SELECT 15 AS [Hour]
UNION ALL SELECT 16 AS [Hour] UNION ALL SELECT 17 AS [Hour] UNION ALL SELECT 18 AS [Hour] UNION ALL SELECT 19 AS [Hour] UNION ALL SELECT 20 AS [Hour]
UNION ALL SELECT 21 AS [Hour] UNION ALL SELECT 22 AS [Hour] UNION ALL SELECT 23 AS [Hour] UNION ALL SELECT 24 AS [Hour]
) as hours_table
) AS A
LEFT OUTER JOIN
(
SELECT
userlog.SessionID,
MAX(CASE WHEN userlog.LogType = 'LOGON'
THEN CONVERT(DATETIME,
LTRIM(RTRIM(CONVERT(NVARCHAR(10), YEAR(userlog.[Date]))))
+ '-' + RIGHT('0' + LTRIM(RTRIM(CONVERT(NVARCHAR(10), MONTH(userlog.[Date])))), 2)
+ '-' + RIGHT('0' + LTRIM(RTRIM(CONVERT(NVARCHAR(10), DAY(userlog.[Date])))), 2)
, 120)
ELSE CONVERT(DATETIME, '1900-01-01', 120)
END) AS [Date_Session_START],
MAX(CASE WHEN userlog.LogType = 'LOGOFF'
THEN CONVERT(DATETIME,
LTRIM(RTRIM(CONVERT(NVARCHAR(10), YEAR(userlog.[Date]))))
+ '-' + RIGHT('0' + LTRIM(RTRIM(CONVERT(NVARCHAR(10), MONTH(userlog.[Date])))), 2)
+ '-' + RIGHT('0' + LTRIM(RTRIM(CONVERT(NVARCHAR(10), DAY(userlog.[Date])))), 2)
, 120)
ELSE CONVERT(DATETIME, '1900-01-01', 120)
END) AS [Date_Session_END],
MAX(CASE WHEN userlog.LogType = 'LOGON' THEN DATEPART(HOUR, userlog.[Date]) ELSE 0 END) AS [Hour_Session_START],
MAX(CASE WHEN userlog.LogType = 'LOGOFF' THEN DATEPART(HOUR, userlog.[Date]) ELSE 0 END) AS [Hour_Session_END],
FROM
userlog
GROUP BY
userlog.SessionID
) AS B
ON (A.[Date] >= B.[Date_Session_START] AND A.[Date] <= B.[Date_Session_END])
AND (A.[Hour] >= B.[Hour_Session_START] AND A.[Hour] <= B.[Hour_Session_END])
WHERE
A.[Date] Between @X and @Y
GROUP BY
A.[Date],
A.[Hour]
【讨论】:
嗨,结果看起来有点低 - 您的查询是计算每小时的登录事件数还是每小时的活动会话数(即,如果用户没有' t 尚未注销但已在前一小时登录)。编辑 - 对不起,我也想感谢你的回答:) 没问题 :) 请告诉哪些行应该被破解以得到结果?全部或LogType = 'LOGON'
或LogType = 'LOGOFF'
- 它应该计算每小时的会话数或用户数吗?或者每个用户每小时的会话数?
当一天中的时间等于或大于 LOGON 日期时间的时间但小于或等于 LOGOFF 日期时间的时间的任何会话时,它应该计入一天中的每个小时。
情况如何:用户User1
在13点到14点之间登录了2次,则有4条记录User1, Session1, LOGON
、User1, Session1, LOGOFF
、User1, Session2, LOGON
、User1, Session2, LOGOFF
。应该算数:Hour 13: 1
还是 Hour 13: 2
?应该考虑什么:一小时内的不同用户或不同的会话?
实际上这不会发生,恐怕这是我的错。它们仅限于每个用户一个会话。【参考方案2】:
好的,采取了稍微不同的方法。我建立了一个登录/注销表——它可能在一个 cte 中,但我不是一个 oracle 专家,所以不确定它是否支持更简单的 SQL 和一个临时表。根据您上面的回答,我已经为 0-30 构建了一个静态整数表(也称为计数表)来处理我的查询中的测试日期范围 - 如果您已经有一个,您可以使用该范围向下并保存一些努力。运行查询会返回一个这样的表(也使用下面的示例数据)
StartDate WorkingHour LoggedInUsers
2002-10-17 00:00:00.000 10 0
2002-10-17 00:00:00.000 11 0
2002-10-17 00:00:00.000 12 0
2002-10-17 00:00:00.000 13 0
2002-10-17 00:00:00.000 14 2
2002-10-17 00:00:00.000 15 5
2002-10-17 00:00:00.000 16 3
2002-10-17 00:00:00.000 17 2
2002-10-17 00:00:00.000 18 2
2002-10-17 00:00:00.000 19 1
2002-10-17 00:00:00.000 20 1
2002-10-17 00:00:00.000 21 1
2002-10-17 00:00:00.000 22 1
2002-10-17 00:00:00.000 23 0
代码在 sql 中运行
DECLARE @StartDate DATETIME ,
@NoDays INT ;
select
@StartDate = '2002-10-01',
@NoDays = 20;
DECLARE @Sessions TABLE (
UserRef UNIQUEIDENTIFIER,
DATE DATETIME,
LogType VARCHAR(100),
SessionID UNIQUEIDENTIFIER
);
INSERT INTO @Sessions
SELECT '96AD647C-D061-43F5-9F8D-FA6C74817E07', '2002-10-17 14:11:25.763', 'LOGON', '8D451569-0260-46BB-9B9E-F49B3E778161'
UNION SELECT '96AD647C-D061-43F5-9F8D-FA6C74817E07', '2002-10-17 18:11:32.547', 'LOGOFF', '8D451569-0260-46BB-9B9E-F49B3E778161'
UNION SELECT '60738820-5F72-4E20-A070-57E07C83B6DE', '2002-10-17 14:53:31.153', 'LOGON', 'C773894C-8B2D-4054-A550-3F04B4C5669F'
UNION SELECT '60738820-5F72-4E20-A070-57E07C83B6DE', '2002-10-17 22:55:25.607', 'LOGOFF', 'C773894C-8B2D-4054-A550-3F04B4C5669F'
UNION SELECT '90A55FDD-967E-4D99-96DF-96840CDB2CDF', '2002-10-17 15:26:40.123', 'LOGON', '1CE5F5A5-4E20-4D4A-BB67-EB0CB33976D7'
UNION SELECT '96AD647C-D061-43F5-9F8D-FA6C74817E07', '2002-10-17 15:51:28.590', 'LOGON', '7EFDEE1C-15CF-4DE1-B59F-7AFC49B4BE73'
UNION SELECT '90A55FDD-967E-4D99-96DF-96840CDB2CDF', '2002-10-17 15:58:05.217', 'LOGOFF', '1CE5F5A5-4E20-4D4A-BB67-EB0CB33976D7'
UNION SELECT '96AD647C-D061-43F5-9F8D-FA6C74817E07', '2002-10-17 15:58:31.013', 'LOGOFF', '7EFDEE1C-15CF-4DE1-B59F-7AFC49B4BE73'
UNION SELECT '90A55FDD-967E-4D99-96DF-96840CDB2CDF', '2002-10-17 15:58:32.733', 'LOGON', '03F56AB8-FED5-4CC7-8445-26BF55F58E60'
UNION SELECT '90A55FDD-967E-4D99-96DF-96840CDB2CDF', '2002-10-17 16:13:02.827', 'LOGOFF', '03F56AB8-FED5-4CC7-8445-26BF55F58E60';
DECLARE @staticintegers TABLE (myInteger INT);
INSERT INTO @staticintegers
SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8
UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13
UNION SELECT 14 UNION SELECT 15 UNION SELECT 16 UNION SELECT 17 UNION SELECT 18
UNION SELECT 19 UNION SELECT 20 UNION SELECT 21 UNION SELECT 22 UNION SELECT 23
UNION SELECT 24 UNION SELECT 25 UNION SELECT 26 UNION SELECT 27 UNION SELECT 28
UNION SELECT 29 UNION SELECT 30 UNION SELECT 31 UNION SELECT 32 UNION SELECT 33;
DECLARE @sessionsOutput TABLE (SessionID UNIQUEIDENTIFIER, StartTime DATETIME, EndTime DATETIME);
INSERT INTO @sessionsOutput
(SessionID, StartTime)
SELECT
SessionID,
[date]
FROM
@Sessions
WHERE logtype = 'Logon';
UPDATE @sessionsOutput
SET EndTime = [date]
FROM @sessionsOutput aa
INNER JOIN @Sessions bb
ON aa.SessionID = bb.SessionID
WHERE bb.LogType = 'Logoff';
SELECT
DATEADD(dd, DateIntegers.myInteger, @StartDate) AS StartDate
,hoursintegers.myINteger AS WorkingHour
,COUNT(aa.SessionID) AS LoggedInUsers
FROM
@staticintegers DateIntegers
LEFT OUTER JOIN @StaticIntegers HoursIntegers
ON HoursIntegers.myInteger BETWEEN 0 AND 23
LEFT OUTER JOIN @sessionsOutput aa
ON
HoursIntegers.myInteger BETWEEN DATEPART(hh, aa.StartTime) AND DATEPART(hh, aa.endtime)
AND CAST(aa.StartTime AS DATE) = DATEADD(dd, dateintegers.myInteger, @StartDate)
GROUP BY
DATEADD(dd, DateIntegers.myInteger, @StartDate),
HoursIntegers.myInteger
ORDER BY
DATEADD(dd, DateIntegers.myInteger, @StartDate),
HoursIntegers.myInteger;
【讨论】:
嗨!谢谢你。但是,我还没有让它工作;我不得不摆弄 SQL,因为它抱怨没有声明变量(我添加了 SET 位),然后关于 date 不是有效类型。无论如何,我让它运行了,它每小时返回 0。 自从我使用 SQL 2005 以来已经有一段时间了;连接到一个并尝试过;将标题更改为 - 声明然后选择(不能在评论中执行,但会更新上面的查询)这样做允许我运行 2005 年提交的查询,而无需向下滚动到第 17 个(根据您的示例数据 - 查询从我在示例中使用的 2002 年 10 月 1 日作为示例数据之前的开始日期的任何天返回)我仍然可以看到发布的结果。以上是关于怎样用sql查询一段时间内一天中的空闲时间和工作时间的主要内容,如果未能解决你的问题,请参考以下文章
提取关于0值的时间,求一天中的多个工作时间,在MongoDB数组操作中
SQL:是不是可以将 dd-mon-yy 转换为一天中的某个时间?