MySql 计数事件实例

标签 mysql if-statement case

所以我有一个每 5 分钟记录一次的事件日志,所以我的日志看起来像这样:

OK
Event1
Event1
Event1
OK
Event1
OK
Event1
Event1
Event1
OK

在本例中,我有 3 个“Event1”实例,因为返回该状态的时间段之间有一个“OK”时间段。

有没有一些不错的方法可以通过 mySql 处理这个问题? (请注意,除了 Event1/OK 之外,还有其他状态经常出现)

实际的Sql结构看起来像这样:

-Historical
    --CID //Unique Identifier, INT, AI
    --ID  //Unique Identifier for LOCATION, INT
    --LOCATION //Unique Identifier for Location, this is the site name, VarChar
    --STATUS //Pulled from Software event logger, VarChar
    --TIME //Pulled from Software event logger, DateTime

最佳答案

另一个答案使用完全不同的方式:-

SELECT MAX(@Counter) AS EventCount -- Get the max counter
FROM (SELECT @Counter:=@Counter + IF(status = 'OK' AND @PrevStatus = 1, 1, 0), -- If it is an OK record and the prev status was not an OK then add 1 to the counter
@PrevStatus:=CASE 
                WHEN status = 'OK' THEN @PrevStatus := 2 -- An OK status so save as a prev status of 2
                WHEN status != 'OK' AND @PrevStatus != 0 THEN @PrevStatus := 1 -- A non OK status but when there has been a previous OK status
                ELSE @PrevStatus:=0 -- Set the prev status to 0, ie, for a record where there is no previous OK status
            END
FROM (SELECT * FROM historical ORDER BY TimeStamp) a
CROSS JOIN (SELECT @Counter:=0, @PrevStatus := 0) b -- Initialise counter and store of prev status.
)c

这是使用用户变量。它有一个子选择来按正确的顺序获取记录,然后使用用户变量来存储先前状态的代码。从 0 开始,当发现状态为 OK 时,会将前一个状态设置为 2。如果发现状态不是 OK,则将前一个状态设置为 1,但仅当前一个状态不为 0 时(即,它已发现状态为“OK”)。在存储上一个状态码之前,如果当前状态为 OK 并且上一个状态码为 1,则将计数器加 1,否则加 0(即不添加任何内容)

然后它只是在外部有一个选择来选择计数器的最大值。

似乎可以工作,但很难阅读!

编辑 - 处理多个 id

SELECT id, MAX(aCounter) AS EventCount -- Get the max counter for each id
FROM (SELECT id,
@PrevStatus:= IF(@Previd = id, @PrevStatus, 0), -- If the id has changed then set the store of previous status to 0
status,
@Counter:=IF(@Previd = id, @Counter + IF(status = 'OK' AND @PrevStatus = 1, 1, 0), 0) AS aCounter,  -- If it is an OK record and the prev status was not an OK and was for the same id then add 1 to the counter
@PrevStatus:=CASE 
                WHEN status = 'OK' THEN @PrevStatus := 2 -- An OK status so save as a prev status of 2
                WHEN status != 'OK' AND @PrevStatus != 0 THEN @PrevStatus := 1 -- A non OK status but when there has been a previous OK status
                ELSE @PrevStatus:=0 -- Set the prev status to 0, ie, for a record where there is no previous OK status
            END,
@Previd := id
FROM (SELECT * FROM historical ORDER BY id, TimeStamp) a
CROSS JOIN (SELECT @Counter:=0, @PrevStatus := 0, @Previd := 0) b
)c
GROUP BY id -- Group by clause to allow the selection of the max counter per id

可读性更差!

另一个选项,再次使用用户变量来生成序列号:-

SELECT Sub1.id, COUNT(DISTINCT Sub1.aCounter) -- Count the number of distinct Sub1 records found for an id (without the distinct counter it would count all the recods between OK status records)
FROM (
    SELECT id,
    `TimeStamp`,
    @Counter1:=IF(@Previd1 = id, @Counter1 + 1, 0) AS aCounter, -- Counter for this status within id
    @Previd1 := id -- Store the id, used to determine if the id has changed and so whether to start the counters at 0 again
    FROM (SELECT * FROM historical WHERE status = 'OK' ORDER BY id, `TimeStamp`) a -- Just get the OK status records, in id / timestamp order
    CROSS JOIN (SELECT @Counter1:=0, @Previd1 := 0) b -- Initialise the user variables.
) Sub1
INNER JOIN (SELECT id,
    `TimeStamp`,
    @Counter2:=IF(@Previd2 = id, @Counter2 + 1, 0) AS aCounter,-- Counter for this status within id
    @Previd2 := id-- Store the id, used to determine if the id has changed and so whether to start the counters at 0 again
    FROM (SELECT * FROM historical WHERE status = 'OK' ORDER BY id, `TimeStamp`) a -- Just get the OK status records, in id / timestamp order
    CROSS JOIN (SELECT @Counter2:=0, @Previd2 := 0) b -- Initialise the user variables.
) Sub2
ON Sub1.id = Sub2.id -- Join the 2 subselects based on the id
AND Sub1.aCounter + 1 = Sub2.aCounter -- and also the counter. So Sub1 is an OK status, while Sub2 the the next OK status for that id
INNER JOIN historical Sub3 -- Join back against historical
ON Sub1.id = Sub3.id -- on the matching id
AND Sub1.`TimeStamp` < Sub3.`TimeStamp` -- and where the timestamp is greater than the timestamp in the Sub1 OK record
AND Sub2.`TimeStamp` > Sub3.`TimeStamp` -- and where the timestamp is less than the timestamp in the Sub2 OK record
GROUP BY Sub1.id -- Group by the Sub1 id

这只是为了状态 OK 记录而抓取表两次,每次添加一个序列号并匹配 id 匹配的位置,并且第二个副本上的序列号比第一个副本大 1(即,它正在查找每个确定,然后立即确定)。然后将其与 id 匹配且时间戳位于 2 个 OK 记录之间的表连接起来。然后计算每个 id 的第一个计数器的不同出现次数。

这应该更具可读性。

关于MySql 计数事件实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17298948/

相关文章:

MySql查询: Getting a record count within query

php - 如何显示 |隐藏链接一段时间

mysql - 错误 3001 Excel VBA MySQL 选择

mysql - #1064 使用 case for rand() 创建过程时出现语法错误

sql-server - SQL Server IIF 与 CASE

mysql - 每次在 magento 中使用某个优惠券代码时,如何查看完整的订单详细信息?

java - If 语句不能与 OR 运算符一起使用

c# - UWP - 在特定条件下在 ListView 中显示数据库

MySql 忽略案例

mysql 条件查询内连接