我有一个包含以下列的表
userid,
game,
gameStarttime datetime,
gameEndtime datetime,
startdate datetime,
currentdate datetime
我可以检索所有的播放时间,但我想计算每天的总播放时间和0或如果游戏没有在特定的一天播放,则为空。
答案 0 :(得分:2)
查看DATEDIFF
进行时间计算。您的要求不是很清楚,但它应该适用于您想要做的任何事情。
您的最终结果可能如下所示:
SELECT
userid,
game,
DATEDIFF(SS, gameStarttime, gameEndtime) AS [TotalSeconds]
FROM [source]
GROUP BY
userid,
game
在上面的示例查询中,SS
计算两个日期之间的秒数(假设两者都不为空)。如果您只需要几分钟,那么MI
将提供总分钟数。但是,我想总秒数是最好的,这样你就可以转换成你需要准确的任何计量单位,例如可能的小时数" 1.23"或类似的东西。
同样,大多数情况都是基于假设以及您似乎在寻找什么的推测。希望有所帮助。
DATEDIFF的MSDN文档:https://msdn.microsoft.com/en-us/library/ms189794.aspx
如果您需要分钟和秒钟,也可以查看DATEPART。
根据反馈更新
下面的查询按天划分小时细分,将时间分成多天,并显示" 0"没有比赛的日子。此外,对于您的输出,我必须假设您有一个单独的用户表(这样您就可以显示在您的日期范围内没有时间的用户)。
-- Define start date
DECLARE @BeginDate DATE = '4/21/2015'
-- Create sample data
DECLARE @Usage TABLE (
userid int,
game nvarchar(50),
gameStartTime datetime,
gameEndTime datetime
)
DECLARE @Users TABLE (
userid int
)
INSERT @Users VALUES (1)
INSERT @Usage VALUES
(1, 'sample', '4/25/2015 10pm', '4/26/2015 2:30am'),
(1, 'sample', '4/22/2015 4pm', '4/22/2015 4:30pm')
-- Generate list of days in range
DECLARE @DayCount INT = DATEDIFF(DD, @BeginDate, GETDATE()) + 1
;WITH CTE AS (
SELECT TOP (225) [object_id] FROM sys.all_objects
), [Days] AS (
SELECT TOP (@DayCount)
DATEADD(DD, ROW_NUMBER() OVER (ORDER BY x.[object_id]) - 1, @BeginDate) AS [Day]
FROM CTE x
CROSS JOIN CTE y
ORDER BY
[Day]
)
SELECT
[Days].[Day],
Users.userid,
SUM(COALESCE(CONVERT(MONEY, DATEDIFF(SS, CASE WHEN CONVERT(DATE, Usage.gameStartTime) < [Day] THEN [Day] ELSE Usage.gameStartTime END,
CASE WHEN CONVERT(DATE, Usage.gameEndTime) > [Day] THEN DATEADD(DD, 1, [Days].[Day]) ELSE Usage.gameEndTime END)) / 3600, 0)) AS [Hours]
FROM [Days]
CROSS JOIN @Users Users
LEFT OUTER JOIN @Usage Usage
ON Usage.userid = Users.userid
AND [Days].[Day] BETWEEN CONVERT(DATE, Usage.gameStartTime) AND CONVERT(DATE, Usage.gameEndTime)
GROUP BY
[Days].[Day],
Users.userid
上面的查询产生了以下样本数据的输出:
Day userid Hours
---------- ----------- ---------------------
2015-04-21 1 0.00
2015-04-22 1 0.50
2015-04-23 1 0.00
2015-04-24 1 0.00
2015-04-25 1 2.00
2015-04-26 1 2.50
2015-04-27 1 0.00
答案 1 :(得分:1)
我已经在sql小提琴上编辑了我的sql,我想这可能会让你得到你所要求的。对我来说,它看起来比你接受的答案要简单得多。
DECLARE @FromDate datetime, @ToDate datetime
SELECT @Fromdate = MIN(StartDate), @ToDate = MAX(currentDate)
FROM Games
-- This recursive CTE will get you all dates
-- between the first StartDate and the last CurrentDate on your table
;WITH AllDates AS(
SELECT @Fromdate As TheDate
UNION ALL
SELECT TheDate + 1
FROM AllDates
WHERE TheDate + 1 <= @ToDate
)
SELECT UserId,
TheDate,
COALESCE(
SUM(
-- When the game starts and ends in the same date
CASE WHEN DATEDIFF(DAY, GameStartTime, GameEndTime) = 0 THEN
DATEDIFF(HOUR, GameStartTime, GameEndTime)
ELSE
-- when the game starts in the current date
CASE WHEN DATEDIFF(DAY, GameStartTime, TheDate) = 0 THEN
DATEDIFF(HOUR, GameStartTime, DATEADD(Day, 1, TheDate))
ELSE -- meaning the game ends in the current date
DATEDIFF(HOUR, TheDate, GameEndTime)
END
END
),
0) As HoursPerDay
FROM (
SELECT DISTINCT UserId,
TheDate,
CASE
WHEN CAST(GameStartTime as Date) = TheDate
THEN GameStartTime
ELSE NULL
END As GameStartTime, -- return null if no game started that day
CASE
WHEN CAST(GameEndTime as Date) = TheDate
THEN GameEndTime
ELSE NULL
END As GameEndTime -- return null if no game ended that day
FROM Games CROSS APPLY AllDates -- This is where the magic happens :-)
) InnerSelect
GROUP BY UserId, TheDate
ORDER BY UserId, TheDate
OPTION (MAXRECURSION 0)