如何找到我的 sql 服务器数据库中所有用户每天的总游戏时间
How to find the total playing time per day for all the users in my sql server database
我有一个 table,其中包含以下列
userid,
game,
gameStarttime datetime,
gameEndtime datetime,
startdate datetime,
currentdate datetime
我可以检索所有游戏时间,但我想计算每天的总游戏时间,如果在特定日期未玩游戏,则为 0 或 null。
查看 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”。此外,对于您的输出,我必须假设您有一个单独的 table 用户(这样您就可以显示在您的日期范围内没有时间的用户)。
-- 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
我已经在 sql fiddle 上编辑了我的 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)
我有一个 table,其中包含以下列
userid,
game,
gameStarttime datetime,
gameEndtime datetime,
startdate datetime,
currentdate datetime
我可以检索所有游戏时间,但我想计算每天的总游戏时间,如果在特定日期未玩游戏,则为 0 或 null。
查看 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”。此外,对于您的输出,我必须假设您有一个单独的 table 用户(这样您就可以显示在您的日期范围内没有时间的用户)。
-- 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
我已经在 sql fiddle 上编辑了我的 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)