如何计算每分钟的登录次数,如果结果为null则返回零

时间:2016-03-04 00:21:44

标签: sql-server

似乎有很多关于这个主题的信息,但是我没有足够的SQL知识来应用它来解决我的问题。

这是我目前正在使用的查询:

/* Number of successful logins per minute for a given date range */
SELECT
         DATEADD(minute, DATEDIFF(minute, 0, AuditMessage.EventDateTime), 0) AS Time, 
         COUNT(AuditMessage.EventTypeCodeUid) AS CountSuccessfulLoginAttemptsPerMinute
FROM     IRWSDB.dbo.AuditMessage
JOIN     AuditEventTypeCode
ON       AuditEventTypeCode.EventTypeCodeUid = AuditMessage.EventTypeCodeUid
WHERE    AuditEventTypeCode.DisplayName = 'Login' 
         AND AuditMessage.EventDateTime >= CONVERT(DATETIME, '2016-03-03 00:00:00', 120) 
         AND AuditMessage.EventDateTime <= CONVERT(DATETIME, '2016-03-04 00:00:00', 120)
GROUP BY DATEADD(minute, DATEDIFF(minute, 0, AuditMessage.EventDateTime), 0)
ORDER BY DATEADD(minute, DATEDIFF(minute, 0, AuditMessage.EventDateTime), 0)

示例输出(按预期工作):

          Time               CountSuccessfulLoginAttemptsPerMinute

2016-03-03 17:48:00.000        1

2016-03-03 17:49:00.000        1

2016-03-03 17:50:00.000        1

2016-03-03 17:55:00.000        2

期望输出:

Time                         CountSuccessfulLoginAttemptsPerMinute

2016-03-03 17:48:00.000        1

2016-03-03 17:49:00.000        1

2016-03-03 17:50:00.000        1

2016-03-03 17:51:00.000        0

2016-03-03 17:52:00.000        0

2016-03-03 17:53:00.000        0

2016-03-03 17:54:00.000        0

2016-03-03 17:55:00.000        2

我试图修改上面的查询以获得所需的输出,但是我走下去的每一条路都是死路一条。任何帮助将不胜感激。谢谢。

3 个答案:

答案 0 :(得分:1)

如果您的数据库没有一天中的每一分钟,它将无法获得所需的输出。除非你后端/任何会在每分钟将一条记录插入你的桌子或参考这个链接Fill empty dates in a matrix SSRS。然后你可以像这样修改你的查询

SELECT
         DATEADD(minute, DATEDIFF(minute, 0, AuditMessage.EventDateTime), 0) AS Time, 
         ISNULL(COUNT(AuditMessage.EventTypeCodeUid),0) AS CountSuccessfulLoginAttemptsPerMinute
FROM     IRWSDB.dbo.AuditMessage
JOIN     AuditEventTypeCode
ON       AuditEventTypeCode.EventTypeCodeUid = AuditMessage.EventTypeCodeUid
WHERE    AuditEventTypeCode.DisplayName = 'Login' 
         AND AuditMessage.EventDateTime >= CONVERT(DATETIME, '2016-03-03 00:00:00', 120) 
         AND AuditMessage.EventDateTime <= CONVERT(DATETIME, '2016-03-04 00:00:00', 120)
GROUP BY DATEADD(minute, DATEDIFF(minute, 0, AuditMessage.EventDateTime), 0)
ORDER BY DATEADD(minute, DATEDIFF(minute, 0, AuditMessage.EventDateTime), 0)

答案 1 :(得分:0)

首先,您需要生成日期范围内的所有分钟。为此,您需要Tally Table。然后对原始查询执行LEFT JOIN

DECLARE @start  DATETIME,
        @end    DATETIME

SELECT @start = '20160303', @end = '20160304'

;WITH E1(N) AS(
    SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b),
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b),
CteTally(N) AS(
    SELECT TOP(DATEDIFF(MINUTE, @start, @end) + 1) ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
    FROM E4
),
CteMinute(dt) AS(
    SELECT  dt = DATEADD(MINUTE, N-1, @start) FROM CteTally
)
SELECT
    cm.dt AS [Time],
    ISNULL(t.cnt, 0) AS CountSuccessfulLoginAttemptsPerMinute
FROM CteMinute cm
LEFT JOIN (
    SELECT 
        DATEADD(MINUTE, DATEDIFF(MINUTE, 0, am.EventDateTime), 0) AS [Time],
        COUNT(am.EventTypeUid) AS cnt
    FROM IRWSDB.dbo.AuditMessage am
    INNER JOIN AuditEventTypeCode atc
        ON atc.EventTypeCodeUid = am.EventTypeCodeUid
    WHERE
        atc.DisplayName = 'Login'
        AND am.EventDateTime >= @start
        AND am.EventDateTime <= @end
    GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, 0, am.EventDateTime), 0)
) t
    ON cm.dt = t.[Time]
GROUP BY cm.dt

答案 2 :(得分:0)

一种方法是使用LEFT JOIN&#34;每分钟列表&#34;到您当前的查询 第二种方法是UNION ALL使用&#34;每分钟列表的当前查询&#34;然后在Count

上执行SUM

有很多方法可以创建每个分钟的列表&#34;比如使用tally / number表,递归cte,交叉连接等。

这是一个使用递归cte

的方法
;with minutes as
(
    select Time = convert(datetime, '2016-03-03')
    union all
    select Time = dateadd(minute, 1, Time)
    from   minutes
    where  Time < '2016-03-05'
)
select Time
from   minues

方法1:LEFT JOIN

;with minutes as
(
    select Time = convert(datetime, '2016-03-03')
    union all
    select Time = dateadd(minute, 1, Time)
    from   minutes
    where  Time < '2016-03-05'
),
data as
(
    < your current query here without the order by clause> 
)
select m.Time, isnull(CountSuccessfulLoginAttemptsPerMinute, 0) as CountSuccessfulLoginAttemptsPerMinute
from   minues m
       left join data d on m.Time = d.Time

方法2:UNION ALL

;with minutes as
(
    select Time = convert(datetime, '2016-03-03')
    union all
    select Time = dateadd(minute, 1, Time)
    from   minutes
    where  Time < '2016-03-05'
)
select Time, sum(CountSuccessfulLoginAttemptsPerMinute) as CountSuccessfulLoginAttemptsPerMinute
FROM
(
     < your current query here without the order by clause> 
     union all
     select Time, 0 as CountSuccessfulLoginAttemptsPerMinute
     from   mintues
) d
group by Time