MS SQL GROUPED SUM

时间:2015-01-14 11:18:10

标签: sql sql-server sum

我目前有一个MS SQL查询,用于计算每个用户在一天内登录系统的时间长度。我从记录中提取此信息的表每个都作为单独的记录登录/注销。目前,我的MS SQL代码如下:

SELECT 
    CAST(DateTime As Date), 
    UserID, 
    MIN(DateTime),
    MAX(DateTime),
    DATEDIFF(SS, MIN(DateTime), MAX(DateTime))
FROM 
    LoginLogoutData 
WHERE 
    CAST(DateTime AS DATE) = '01/01/2015' 
GROUP BY 
    CAST(DateTime As Date), 
    UserID

这可以根据需要运行,并创建一个类似于下面的表。

    Date        UserID  FirstLogIn   FinalLogOut    LoggedInTime
  .........     ......  ..........   ............   ............
  01/01/2015    ABC     07:42:57     14:57:13         26056    
  01/01/2015    DEF     07:45:49     13:57:56         22326  

这适用于一天的数据。但是,如果我想计算某人在更大的日期范围内登录系统的时间长度,例如一个星期或一个月,这不起作用;它会计算用户在第一天登录和退出最后一天之间的时间长度。

基本上,我希望我的代码计算(Max(DateTime) - Min(DateTime)) FOR EACH DAY ,然后将所有这些值合并为一个仅由UserId分组的简单表格。然后,我可以随意设置我的日期范围,并收到正确的结果。

所以我的表格如下:

  UserId     LoggedInTime
 ........   ............. 
    ABC         563287
    DEF         485823
    GEH         126789

我认为我需要在GROUP BY函数中使用MIN(),但我还没有太多经验。

有没有人有这方面的经验?任何帮助将不胜感激。

谢谢。

4 个答案:

答案 0 :(得分:1)

首先,您需要按日期汇总,然后按较大的时间单位汇总。例如,今年迄今为止:

SELECT UserId, SUM(diffsecs)
FROM (SELECT CAST(DateTime As Date) as thedate, UserID,
             DATEDIFF(second, MIN(DateTime), MAX(DateTime)) as diffsecs
      FROM LoginLogoutData
      GROUP BY CAST(DateTime As Date), UserID
     ) ud
WHERE thedate between '2015-01-01' and getdate();

答案 1 :(得分:0)

由于您已经为每个日期计算LoggedInTime,因此需要进行以下查询

SELECT USERID,SUM(LoggedInTime) LoggedInTime
FROM YOURTABLE
GROUP BY USERID

<强>更新

由于您有一条登录记录和下一条登出记录(无论日期如何),我们可以使用SELF JOIN(一个连接自身的表)的概念来获取相应登录时间的注销日期时间。

DECLARE @FROMDATE DATETIME='2014-01-01 07:42:57.000'
DECLARE @TODATE DATETIME='2015-02-01 07:42:57.000'    

;WITH CTE AS
(    
    -- ROW_NUMBER() is taken as logic for self joining. 
    SELECT ROW_NUMBER() OVER(ORDER BY USERID,[DATETIME]) RNO,* 
    FROM #TEMP
    WHERE [DATETIME] >= @FROMDATE AND [DATETIME] < @TODATE 
)
,CTE2 AS
(
    -- Since we are using SELF JOIN,we will get the next row's 
    -- datetime(ie, Logout time for corresponding login time)
    SELECT C1.*,C2.[DATETIME] [DATETIME2],
    DATEDIFF(SS, C1.[DateTime], C2.[DateTime]) SECONDSDIFF 
    FROM CTE C1
    LEFT JOIN CTE C2 ON C1.RNO=C2.RNO-1
    WHERE C1.RNO%2 <> 0
    -- Since we get the next row's datetime in current row,
    -- we omit each logout time's row
)
SELECT USERID,SUM(SECONDSDIFF) SECONDSDIFF
FROM CTE2

答案 2 :(得分:0)

您可以对第一个查询使用另一个group by语句,如下所示:

Select UserID,SUM(LoggedTime)
FROM
(
SELECT CAST(DateTime As Date), 
       UserID, MIN(DateTime), 
       MAX(DateTime), 
       DATEDIFF(SS, MIN(DateTime), MAX(DateTime)) AS LoggedTime
FROM LoginLogoutData 
WHERE CAST(DateTime AS DATE) = '01/01/2015'
GROUP BY CAST(DateTime As Date), UserID
) As temp
GROUP BY UserID

您可以在此处更改where子句以匹配数据范围。它将首先计算每天的记录时间,然后获得每个用户所有天数的总和。

答案 3 :(得分:0)

以下是如何使用工作示例数据和包含的T-SQL执行此操作的示例。

 -- original table you described
 CREATE TABLE LoginLogoutData  (UserID int, DateTime DateTime)

 GO

 -- clean any previous sample records
 TRUNCATE TABLE LoginLogOutData

 /*local variables for iteration*/
 DECLARE @i int = 1
 DECLARE @n int
 DECLARE @entryDate DateTime = GETDATE()

 --populate the table with some sample data
 /* for each of the  five sample users, generate sample login and logout 
  data for 30 days. Each login and logout are simply an hour apart for demo purposes. */
 SET NOCOUNT ON

 -- iterate over 5 users (userid)
 WHILE (@i <= 5)
 BEGIN

 --set the initial counter for the date loop 
 SET @n = 1

--dated entry loop
WHILE (@n <= 30)
BEGIN
   -- increment to the next day
   SET @entryDate = DateAdd(dd,@n,GETDATE())

        --logged in entry
        INSERT INTO LoginLogoutData (DateTime, UserID)          
        SELECT @entryDate,@i 

        -- logged out entry
        INSERT INTO LoginLogoutData (DateTime, UserID)
        SELECT DateAdd(hh,1,@entryDate),@i 

    --increment counter 
    SET @n = @n+1
 END

 --increment counter 
 SET @i=@i+1
END

GO


/* demonstrate that for each user each day has entries and that
the code calculates (Max(DateTime) - Min(DateTime)) FOR EACH DAY 
*/
SELECT UserID, 
   MIN(DateTime) AS LoggedIn, 
   MAX(DateTime) AS LoggedOut, 
   DATEDIFF(SS, MIN(DateTime), MAX(DateTime)) AS LoginTime
FROM LoginLogoutData 
GROUP BY CAST(DateTime As Date), UserID

/*this is a table variable used to support the "sum all these values together into one 
simple table grouped only by UserId*/
DECLARE @SummedUserActivity AS TABLE (UserID int, DailyActivity int)



 -- group the subtotals from each day per user 
   INSERT INTO @SummedUserActivity (UserID, DailyActivity)
   SELECT UserID, DATEDIFF(SS, MIN(DateTime), MAX(DateTime))
   FROM LoginLogoutData 
   GROUP BY CAST(DateTime As Date), UserID

   -- demonstrate the sum of the subtotals grouped by userid
   SELECT UserID, SUM(DailyActivity) AS TotalActivity
   FROM @SummedUserActivity
   GROUP BY UserID