MySQL: 检查子串序列

MySQL: Check substring sequence

我在 MySQL 中有一个 table,其中包含此字段 SERVICE,DATE_STATE,STATE:

SERVICE DATE_STATE      STATE
aaaaa   '2019-12-01'    OK
aaaaa   '2019-12-03'    KO
aaaaa   '2019-12-04'    OK
...
xxxxx   '2019-12-07'    OK
xxxxx   '2019-12-09'    KO

记录在服务更改其状态的日期注册。

我想检查状态序列是否为 OK-KO 交替(依此类推,无限期地像 OK-KO-OK-KO-OK),当按服务分组并按日期排序时。 比如像OK-OK或KO-KO这样的序列或子序列是禁止的,我想检查和检测它们。

我不知道如何找到解决方案。

使用此查询:

SELECT service, 
        GROUP_CONCAT(state ORDER BY date_state) AS sequence_state 
FROM T
group by service

我在一个字符串中有完整的序列 'OK,KO,OK,KO...' 但我不知道如何检查字符串中的交替。

如有任何帮助,我们将不胜感激。非常感谢

这是我的想法。尝试按州对所有偶数行进行分组。如果输出的计数大于 1,您就知道有问题。 试试这个:

SELECT IF(COUNT(*)=1, 'Clear','PROBLEM') AS CheckFlag FROM (
SELECT state FROM (
SELECT t.*
FROM (SELECT t.*, (@rn := @rn + 1) AS seqnum
      FROM t CROSS JOIN
           (SELECT @rn := 0) vars
     ) t
WHERE MOD(seqnum, 2) = 0) a
GROUP BY state
) a

不是最好的解决方案,但它会起作用!

将其用作示例数据:

CREATE TABLE services (
   SERVICE varchar(50), 
   DATE_STATE date, 
   STATE varchar(2));


INSERT INTO services VALUES
  ("normal1", DATE("2000-01-01"), "OK"),
  ("normal1", DATE("2000-01-01"), "KO"),
  ("double ok", DATE("2000-01-01"), "OK"),
  ("double ok", DATE("2000-01-01"), "OK"),
  ("double ko", DATE("2000-01-01"), "KO"),
  ("double ko", DATE("2000-01-01"), "KO");

我创建了这个查询,它使用 LEAD window 函数为您提供了所需的结果:

SELECT * FROM
(SELECT 
 SERVICE, 
 DATE_STATE, 
 STATE, 
 LEAD(STATE) 
    OVER (PARTITION BY SERVICE 
          ORDER BY DATE_STATE) AS NEXT_STATE
FROM services) AS services_with_next_state
WHERE STATE=NEXT_STATE;

在此处查看实际效果:https://www.db-fiddle.com/f/eMHRzJ6hN6xx4x2PjSLFXb/0

经过一些测试和阅读,我认为正确答案是:

  1. 如果您使用的是 MySQL 8.0 或更高版本,@cargo23 的回答非常有效。
  2. 如果你使用旧版本,一些pirouette必须这样做。经过一些测试,所有结果都符合我的预期:
    SET @a :=0;
    SET @b :=1;
    SELECT 
        r.service, 
        r.value     AS "previous state", 
        r2.value AS "next state", 
        r.date_state    AS "date_state previous", 
        r2.date_state AS "date_state next" 
    FROM
    (SELECT if(@a, @a:=@a+1, @a:=1) as rownum, service, state as VALUE, date_state FROM services order by service ASC, date_state asc) AS r
    LEFT JOIN
    (SELECT if(@b, @b:=@b+1, @b:=1) as rownum, service, state as VALUE, date_state FROM services order by service ASC, date_state asc) AS r2
    ON (r.rownum+2) = r2.rownum AND r.service = r2.service 
    WHERE
    r.value IS NOT NULL 
    AND r2.value IS NOT NULL
    AND r.value = r2.value
    ORDER BY r.service ASC, r.date_state asc;