如何找到我的 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)

Play with it your self on sql fiddle.