如何查找我的sql server数据库中所有用户每天的总播放时间

时间:2015-04-27 13:23:54

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

我有一个包含以下列的表

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

我可以检索所有的播放时间,但我想计算每天的总播放时间和0或如果游戏没有在特定的一天播放,则为空。

2 个答案:

答案 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)

Play with it your self on sql fiddle.