【问题标题】:How to find the total playing time per day for all the users in my sql server database如何查找我的sql server数据库中所有用户每天的总播放时间
【发布时间】:2015-04-27 13:23:53
【问题描述】:

我有一个包含以下列的表格

userid, 
game, 
gameStarttime datetime, 
gameEndtime datetime, 
startdate datetime,
currentdate datetime

我可以检索所有游戏时间,但我想计算每天的总游戏时间,如果在特定日期没有玩游戏,则为 0 或 null。

【问题讨论】:

  • 添加一些示例数据和预期输出
  • 所以你的主要问题是你想记录从 min(gameStarttime) 到 max(gameEndtime) 的每一天,但没有得到没有人玩的天数?还是您的问题仅仅是您不知道如何计算 gameStarttime 和 gameEndtime 之间的差异?如果您显示您的查询会很好,这样我们就可以看到您走了多远。
  • 我的问题是正确计算一个人从开始日期到今天每天的游戏时间。
  • 这听起来像是你想要一个 /played 功能,比如流行的 MMORPG,它会计算你实际玩游戏的天数和小时数。对吗?

标签: sql sql-server sql-server-2008 sql-server-2008-r2 sql-server-2012


【解决方案1】:

查看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

【讨论】:

  • 谢谢,但我正在寻找更多。我有每个用户的游戏时间段。每天记录一个人的演奏开始时间和演奏结束时间。从那我想看看一个人每天玩了多少。例如,他可能一天玩了 2 小时,另一天玩了 10 小时,另一天玩了 0 小时
  • 那么您是否正在寻找他们每天玩和不玩的记录?例如,您是否需要用户和游戏在他们玩 0 小时的那一天的记录?此外,对于晚上 10 点到凌晨 2 点的用例,您关心的是第 1 天的 4 小时还是应该每天 2 小时?
  • 是的,如果玩了多久。两者都可以。
  • 我认为如果 datediff 输出 == 0 而不是在同一天添加或在第二天添加。
  • 根据您的 cmets 更新答案
【解决方案2】:

我在 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)

Play with it your self on sql fiddle.

【讨论】:

  • 检查小提琴。它只显示播放时间的记录。我正在为所有用户寻找上述输出。
  • 查看我编辑的答案。我必须说这是一个有趣的挑战,即使你接受了另一个答案,如果我成功了,请告诉我。
  • 这次你完全正确。非常感谢。现在我有两种方法可以做到。让我们看看我选择哪一个。
  • 太棒了 :-) 好久没有在 sql 中做一些有趣的事情了,感谢挑战。
  • 那么只需将使用小时的日期差异更改为使用秒的日期差异:DATEDIFF(HOUR, GameStartTime, GameEndTime) 应该是 DATEDIFF(SECOND, GameStartTime, GameEndTime)。不要忘记全部更改
猜你喜欢
  • 2018-07-24
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
  • 2021-07-17
  • 2011-10-26
  • 2011-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多