MS SQL 分组总和

MS SQL GROUPED SUM

我目前有一个 MS SQL 查询,它计算每个用户在一天内登录系统的时间长度。 table 我是从每个日志的记录中提取这些信息in/log 作为单独的记录出来的。目前,我的MSSQL代码如下:

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

这会按要求工作并创建一个类似于下面的 table。

    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)) 每一天 然后将所有这些值加在一起成为一个简单的 table 仅由 UserId。然后我就可以根据需要设置我的日期范围并收到正确的结果。

所以我会有一个 table 如下:

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

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

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

谢谢。

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

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

更新

由于你有一个登录记录和下一个注销记录(与日期无关),我们可以使用 SELF JOIN 的概念(一个加入自身的 table )来获取相应登录的注销日期时间时间.

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

您可以对第一个查询使用另一个 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 子句以匹配数据范围。它会首先计算每天的记录时间,然后得到每个用户所有天数的总和。

首先您需要按日期聚合,然后按更大的时间单位聚合。例如,对于年初至今:

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();

这是一个示例,说明如何使用工作示例数据和 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