【问题标题】:Tricky SQL query involving consecutive values涉及连续值的棘手 SQL 查询
【发布时间】:2012-07-04 13:34:38
【问题描述】:

我需要执行一个相对容易解释但(鉴于我的技能有限)很难编写 SQL 查询。

假设我们有一张类似的表格:

 exam_no | name | surname | result | date
---------+------+---------+--------+------------
 1       | John | Doe     | PASS   | 2012-01-01
 1       | Ryan | Smith   | FAIL   | 2012-01-02 <--
 1       | Ann  | Evans   | PASS   | 2012-01-03
 1       | Mary | Lee     | FAIL   | 2012-01-04
 ...     | ...  | ...     | ...    | ...
 2       | John | Doe     | FAIL   | 2012-02-01 <--
 2       | Ryan | Smith   | FAIL   | 2012-02-02
 2       | Ann  | Evans   | FAIL   | 2012-02-03
 2       | Mary | Lee     | PASS   | 2012-02-04
 ...     | ...  | ...     | ...    | ...
 3       | John | Doe     | FAIL   | 2012-03-01
 3       | Ryan | Smith   | FAIL   | 2012-03-02
 3       | Ann  | Evans   | PASS   | 2012-03-03
 3       | Mary | Lee     | FAIL   | 2012-03-04 <--

请注意,exam_nodate 不一定像我选择的示例中所期望的那样相关。

现在,我需要做的查询如下:

  • 从最新的考试 (exam_no = 3) 中找出所有不及格的学生(John DoeRyan SmithMary Lee)。
  • 为这些学生中的每一个找到连续失败的考试批次中的第一个的日期。另一种说法是:对于这些学生中的每一个,找出他们最后一次通过考试之后的第一次失败考试的日期。 (查看表中的箭头)。

结果表应该是这样的:

 name | surname | date_since_failing
------+---------+--------------------
 John | Doe     | 2012-02-01
 Ryan | Smith   | 2012-01-02
 Mary | Lee     | 2012-03-04

如何执行这样的查询?

感谢您的宝贵时间。

【问题讨论】:

  • 其他读者:注意他将其标记为“MySQL”
  • 认为您可以在 result='FAIL' 上加入同一张表,并从中选择日期最高的表。你试过什么?
  • 最新的考试”是什么意思?考试日期最晚?
  • 我所说的“最新考试”是指exam_no最大的考试。
  • 我已经重写了我的答案,再次检查一下

标签: mysql sql database


【解决方案1】:

您可以利用这样一个事实,即如果某人通过了最近一次考试,那么他们自最近一次通过以来就没有通过任何考试:因此问题归结为发现自最近一次通过以来的第一次考试失败:

SELECT   name, surname, MIN(date) date_since_fail
FROM     results NATURAL LEFT JOIN (
  SELECT   name, surname, MAX(date) lastpass
  FROM     results
  WHERE    result = 'PASS'
  GROUP BY name, surname
) t
WHERE    result = 'FAIL' AND date > IFNULL(lastpass,0)
GROUP BY name, surname

sqlfiddle 上查看。

【讨论】:

  • 就是这样。我无法相信它是多么简洁易懂。我设法以最小的努力使其适应我的实际问题。非常感谢。
【解决方案2】:

我应该使用获取上次通过考试的子查询, 类似于:

SET @query_exam_no = 3;
SELECT
 name,
 surname,
 MIN(IF(date > last_passed_exam, date, NULL)) AS date_failing_since
FROM
 exam_results
 LEFT JOIN (
  SELECT
   name,
   surname, 
   MAX(date) AS last_passed_exam 
  FROM exam_results 
  WHERE result = 'PASS' 
  GROUP BY name, surname
 ) AS last_passed_exams USING (name, surname)
HAVING
 MAX(IF(exam_no = @query_exam_no, result, NULL)) = 'FAIL'
GROUP BY name, surname

【讨论】:

    【解决方案3】:

    这就够了:

    select t.name,
           t.surname,
           t.date as 'date_since_failing'
    from tablename t
    inner join
    (
        select name,
               surname,
               max(exam_no) as exam_no
        from tablename
        group by name, surname
        having min(result) = 'FAIL'
    ) aux on t.name = aux.name and t.surname = aux.surname and t.exam_no = aux.exam_no
    

    【讨论】:

      【解决方案4】:

      你所要求的条件是没有用的,没有它你就做不到。这是工作示例。

      select
        e.name,
        e.sur_name,
        min(e.date) as `LastFailed`
      from exams as e
      where e.result = 'Fail'
      group by e.name
          order by e.name 
      

      这会产生这个结果

      name            sur_name    LastFailed
      Ann         Evans       2012-02-03
      John        Doe         2012-02-01
      Mary        Lee         2012-01-04
      Ryan        Smith       2012-01-02
      

      【讨论】:

      • 这不是我要找的结果。日期应该是我的问题的结果表中出现的日期。我要查找的是这些学生在最近一批连续不及格的考试中第一次不及格的考试日期。
      • 不,抱歉。我正在寻找的结果正是我最初在我的问题中写的。请不要编辑我的问题以使其符合您的结果,这真的很不尊重。
      猜你喜欢
      • 1970-01-01
      • 2016-01-12
      • 1970-01-01
      • 2016-07-26
      • 1970-01-01
      • 2014-02-27
      • 2016-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多