【问题标题】:How to select where there are 2 consecutives rows with a specific value using MySQL?如何使用 MySQL 选择具有特定值的 2 个连续行的位置?
【发布时间】:2016-02-15 21:39:21
【问题描述】:

我正在构建一个系统,可以显示学生连续两天缺课的时间。 例如,此表包含缺勤。

day         |   id  |   missed
----------------------------------
2016-10-6   |   1   |   true
2016-10-6   |   2   |   true
2016-10-6   |   3   |   false

2016-10-7   |   1   |   true
2016-10-7   |   2   |   false
2016-10-7   |   3   |   true

2016-10-10  |   1   |   false
2016-10-10  |   2   |   true
2016-10-10  |   3   |   true

(2016-10-8 和 2016-10-9 是周末)

在上述情况下:

  • 学生 1 错过了第一天和第二天。 (连续)
  • 学生 2 错过了第一天和第三天。 (不连续)
  • 学生 3 错过了第 2 天和第 3 天。 (连续)

查询应该只选择学生 1 和 3。

是否可以仅使用单个 SQL 查询来执行此类操作?

【问题讨论】:

    标签: mysql sql select group-by


    【解决方案1】:

    使用内部联接连接表的两个实例——一个与“第一”天,一个与“第二”天,然后只查找两者都丢失的行:

    select a.id from yourTable as a inner join yourTable as b 
      on a.id = b.id and a.day = b.day-1 
      where a.missed = true and b.missed = true
    

    编辑

    现在您更改了规则...并在日期列中将其设为 date 而不是 int,这就是我要做的:

    1. 使用DAYOFWEEK()函数以数字形式转到一天
    2. 过滤掉周末
    3. 使用模数将星期日作为星期四的第二天:

      select a.id from yourTable as a inner join yourTable as b 
        on a.id = b.id and DAYOFWEEK(a.day) % 5 = DAYOFWEEK(b.day-1) % 5 
        where a.missed = true and b.missed = true
        and DAYOFWEEK(a.day) < 6 and DAYOFWEEK(b.day) < 6
      

    【讨论】:

    • 你没有加入学生证
    • 比它复杂一点。我刚刚编辑了问题。
    【解决方案2】:

    方法与其他答案类似,但语法不同

    select distinct id
    from t
    where
        missed=true and
        exists (
            select day
            from t as t2
            where t.id=t2.id and t.day+1=t2.day and t2.missed=true
        )
    

    【讨论】:

    • 比它复杂一点。我刚刚编辑了问题。
    • @DanielSantos 那么您需要添加 OR 条件,例如 `( (t.day+1=t2.day) 或 (DAYOFWEEK(t.day) == 6 AND t.day+3=t2 .day) )
    【解决方案3】:

    这将为您提供它发生的每个实例。如果连续 3 天或更长时间未命中,您将获得多次点击,因此如果这是一个问题,那么您需要对其进行改进。

    SELECT
        T1.id,
        T1.day
    FROM
        My_Table T1
    INNER JOIN My_Table T2 ON
        T2.id = T1.id AND
        T2.day = T1.day + 1 AND
        T2.missed = true
    WHERE
        T1.missed = true
    

    【讨论】:

    • 比它复杂一点。我刚刚编辑了问题。
    【解决方案4】:

    您可以使用变量来做到这一点:

    SELECT DISTINCT id
    FROM (
      SELECT day, id, missed,
             @rn := IF(@id = id, 
                       IF(missed = true, @rn + 1, 0),
                       IF(@id := id, 
                          IF(missed = true, 1, 0), 
                          IF(missed = true, 1, 0))) AS rn                          
      FROM mytable
      CROSS JOIN (SELECT @rn := 0, @id := 0) AS var
      ORDER BY id, day) AS t
    WHERE t.rn >= 2
    

    上述方法的好处在于它是可扩展的:它可以很容易地扩展到检查超过 2 个连续的学生缺勤记录。

    Demo here

    【讨论】:

    • 比它复杂一点。我刚刚编辑了问题。
    【解决方案5】:

    这是一种方法...

    SELECT x.id
      FROM my_table x
      JOIN my_table y
        ON y.id = x.id 
       AND y.missed = x.missed
       AND y.day > x.day
       AND 5 * (DATEDIFF(y.day, x.day) DIV 7) + MID('0123444401233334012222340111123400001234000123440', 7 * WEEKDAY(x.day) + WEEKDAY(y.day) + 1, 1) <= 1
     WHERE x.missed = 1;
    

    【讨论】:

    猜你喜欢
    • 2016-08-25
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    相关资源
    最近更新 更多