【问题标题】:SQL Server 2012 - Rolling counter with resetSQL Server 2012 - 带有重置的滚动计数器
【发布时间】:2021-02-13 07:47:18
【问题描述】:

我正在使用 SQL Server 2012,并且想要获取登录失败尝试的总数。我的桌子有

| Login_Name | Is_Success | Login_Date |

我的查询是

select login_name, 
sum(case when is_success = 1 THEN 0 ELSE 1 END) over (partition by login_name, issuccess order by login_name, login_date, is_success)
from login_table

查询给了我结果,但我希望在 is_success 变为 1 时重置计数

| Login_Name | Is_Success | Unsuccessful Attempts |
| admin      | 1          | 0                     |
| admin      | 0          | 1                     |
| admin      | 0          | 2                     |
| admin      | 0          | 3                     |
| admin      | 0          | 4                     |
| admin      | 0          | 5                     |
| admin      | 1          | 0                     |
| admin      | 0          | 1                     |

注意:我使用的是 SQL Server 2012

【问题讨论】:

    标签: sql sql-server partition rolling-computation


    【解决方案1】:

    这是一个经典的间隙和孤岛问题。您可以使用带窗口的COUNT 将数据分组,然后对这些组使用ROW_NUMBER

    WITH YourTable AS(
        SELECT *
        FROM (VALUES('admin',1,CONVERT(datetime2(0),'2020-10-30T20:00:00')),
                    ('admin',0,CONVERT(datetime2(0),'2020-10-30T20:01:00')),
                    ('admin',0,CONVERT(datetime2(0),'2020-10-30T20:02:00')),
                    ('admin',0,CONVERT(datetime2(0),'2020-10-30T20:03:00')),
                    ('admin',0,CONVERT(datetime2(0),'2020-10-30T20:04:00')),
                    ('admin',0,CONVERT(datetime2(0),'2020-10-30T20:05:00')),
                    ('admin',1,CONVERT(datetime2(0),'2020-10-30T20:06:00')),
                    ('admin',0,CONVERT(datetime2(0),'2020-10-30T20:07:00')))V(Login_Name,Is_Success,Login_Date)),
    Grps AS(
        SELECT Login_Name,
               Is_Success,
               Login_Date,
               COUNT(CASE Is_Success WHEN 1 THEN 1 END) OVER (PARTITION BY Login_Name ORDER BY Login_Date) AS Grp
        FROM YourTable)
    SELECT Login_NAme,
           Is_Success,
           ROW_NUMBER() OVER (PARTITION BY Login_NAme, Grp ORDER BY Login_Date) -1 AS UnSuccessfulAttempts
    FROM Grps
    ORDER BY Login_Name,
             Grp,
             Login_Date;
    

    【讨论】:

    • 这看起来是正确的方法,我已经赞成 - 但是如果不成功的尝试有一个值(例如,0 或 -1),COUNT(Is_Success) 会起作用吗?您可以使用与他们类似的 COUNT(CASE ...) 。此外,您的 order by 有一个多余的字段 - 也许您的意思是 date?
    • 您可以改用CASE 表达式@seanb。我只是假设它们可能只是 10,这就是您的示例数据所说的。
    • 我尝试运行此查询,但它没有返回结果。 UnSuccessfulAttempts 列始终递增 1
    • 样本数据将帮助我,@Ankit。我只有预期的结果,所以不得不对你的数据做出假设。
    • 我已经更新了对您的数据的假设,@Ankit。正如我所提到的,没有样本数据,只有预期的结果。例如,您有一列 Login_date,我不知道 实际 存储了什么。
    【解决方案2】:

    我假设您正在寻找摘要,而不是细节日志?我会这样处理:

    SELECT login_name, 
     ( SELECT count(*) FROM login_table
        WHERE login_name = lt.login_name
          AND login_date > ( SELECT MAX(login_date) FROM login_table WHERE login_name = lt.login_name AND is_success = 1 )
     ) AS failures
      FROM login_table AS lt
      ORDER BY 1
    

    它是如何工作的:

    内部相关子查询获取用户最后一次成功登录:

    SELECT MAX(login_date) FROM login_table WHERE login_name = lt.login_name AND is_success = 1
    

    外部相关查询:

    ( SELECT count(*) FROM login_table WHERE login_name = lt.login_name AND login_date > --上次成功登录-- ) AS 故障

    计算上次成功后发生的失败次数。 我没有测试过这个。祝你的项目好运!

    【讨论】:

      猜你喜欢
      • 2017-03-23
      • 2015-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-21
      相关资源
      最近更新 更多