SQL组还是在哪里?

时间:2011-09-13 11:01:49

标签: sql sql-server

我有一个表格,用于记录已登录我们系统的用户。它会在登录时和注销时记录。我需要生成一些SQL,它会为我们提供当天的小时数和当时登录的人数列表。我可以这样做一次,但我不知道如何扩展它以产生一天中的每个小时。如果可能,我真的不想做24个SQL语句!?

SELECT     COUNT(userID) AS "count of users"
FROM         LogonTimes
WHERE     (LoginTime > '2011-09-12 09:00:00') AND (LogoffTime < '2011-09-12 10:00:00 ')

上面会产生说“3”。这显示3人在9点到10点之间登录。

任何想法?!

[编辑]这是人们在下面猜到的SQL Server - 抱歉没有指定!我会试试这些建议并尽快回复!谢谢:) [/ edit]

4 个答案:

答案 0 :(得分:2)

对于SQL Server,你可以做...

declare @DayToCheck datetime 
set @DayToCheck = '2011-09-12'

;with C as
(
  select @DayToCheck as H
  union all
  select dateadd(hour, 1, H)
  from C
  where dateadd(hour, 1, H) < dateadd(day, 1, @DayToCheck)
)
select C.H as [hour],
       count(L.userID) as [count of users]
from C
  left outer join LogonTimes as L
    on L.LogoffTime > C.H and 
       L.LoginTime < dateadd(hour, 1, C.H)
group by C.H       

在此尝试:http://data.stackexchange.com/stackoverflow/q/112462/

SQL Server 2000的一个版本,如果是CTE,则使用数字表。这里我使用master..spt_values。

declare @DayToCheck datetime
set @DayToCheck = '2011-09-12'

select dateadd(hour, N.number, @DayToCheck) as [hour],
       count(L.userID) as [count of users]
from master..spt_values as N
  left outer join LogonTimes as L
    on L.LogoffTime > dateadd(hour, N.number, @DayToCheck) and
       L.LoginTime < dateadd(hour, N.number + 1, @DayToCheck)
where N.Type = 'P' and
      N.Number between 0 and 23       
group by dateadd(hour, N.number, @DayToCheck)       

答案 1 :(得分:0)

将LoginTime列舍入到最近的小时,然后将其分组。

至于Martin的观点,如果您希望在时间范围内有用户登录的总计数,您还需要在where子句中添加一些其他条件,即

在当前小时之前登录并在当前小时内退出

在当前时间内登录并在当前时间之后注销

在当前小时之前登录并在当前小时之后注销

您甚至可能需要考虑未记录的注销日期时间,具体取决于您的注销系统的工作方式。

答案 2 :(得分:0)

目前还不清楚你在使用什么环境(SQL SERVER vs. Oracle vs Other)。以下内容将特定于Oracle:

SELECT    
    HOUR_OF_DAY,
    COUNT(userID) AS "count of users"
FROM         LogonTimes,
(
    select TRUNC(SYSDATE)+COUNTER/24  AS HOUR_OF_DAY from 
    (
        select 
            level-1 as COUNTER 
        from dual  
        connect by level <=24
    ) a
    where COUNTER >= 0 
)
WHERE     (LoginTime >= HOUR_OF_DAY) AND (LogoffTime < HOUR_OF_DAY+1/24)

注意:这与您的原始版本一样,计算在一小时内登录的人员,不一定每个人都登录(即他们已经登录,并且保持登录状态几个小时)。

编辑:如果你想捕捉在一小时内任何时候登录的所有人,WHERE子句应该是:

WHERE     (LoginTime < HOUR_OF_DAY+1/24) -- logged in before end of the hour
 AND (LogoffTime > HOUR_OF_DAY) --logged off after start of the hour

答案 3 :(得分:0)

由于您没有指定SQL语言,我将使用SQL Server。我正在使用表值函数,但你可以使用临时表来做同样的事情。所需的功能是:

CREATE FUNCTION [dbo].[NumbersBetween] (
    @start int,
    @end int
) RETURNS @ret TABLE (Num int) AS BEGIN

    DECLARE @x int

    SET @x = @start
    WHILE (@x <= @end) BEGIN
        INSERT INTO @ret VALUES(@x)
        SET @x = @x + 1
    END

    RETURN
END
GO

用于测试的表格是:

CREATE TABLE LogonTimes(
    SessionId int IDENTITY(1,1) NOT NULL PRIMARY KEY,
    LoginTime datetime NOT NULL,
    LogOffTime datetime NULL
)
INSERT INTO LogonTimes(LoginTime, LogOffTime) VALUES('2011-09-12 09:10', '2011-09-12 10:10')

最后,获取所需信息的功能(假设您每天都需要这些信息,而不仅仅是所有日期)

DECLARE @queryDate datetime
SET @queryDate = '2011-09-12'

SELECT DATEADD(hour, hours.Num, @queryDate) AS HourOfDay, COUNT(LogonTimes.SessionId) AS SessionCount
FROM dbo.NumbersBetween(0, 23) hours 
  LEFT JOIN LogonTimes 
    ON LogonTimes.LoginTime < DATEADD(hour, hours.Num + 1, @queryDate) 
      AND ISNULL(LogonTimes.LogOffTime, GETDATE()) > DATEADD(hour, hours.Num, @queryDate)
GROUP BY hours.Num
ORDER BY HourOfDay

这会产生以下结果(截断以删除开头和结尾的空白)

HourOfDay               SessionCount
----------------------- ------------
....
2011-09-12 07:00:00.000 0
2011-09-12 08:00:00.000 0
2011-09-12 09:00:00.000 1
2011-09-12 10:00:00.000 1
2011-09-12 11:00:00.000 0
....

此解决方案会考虑仍在登录的用户,在同一小时内登录和注销的用户以及在午夜过后留下的用户。

-

更新了解决方案,仅考虑查询一天,删除了SQL2008依赖项。