【问题标题】:MySQL Query: 3 tests passed, 1 failedMySQL 查询:3 次测试通过,1 次失败
【发布时间】:2018-03-27 21:26:29
【问题描述】:

我正在尝试编写一个查询,该查询将提取已通过测试 1 到 3 并且未通过测试 4 的学生。

学生可以重新参加考试,因此可能会有不及格的记录,然后是一些考试的通过记录,例如下面的 student_id = 2。

这样的表设置 -

test_id | student_id | status  | completed_on
--------+------------+---------+------------
 1      |    1       | passed  | 2018-03-24 
 2      |    1       | passed  | 2018-03-25 
 3      |    1       | passed  | 2018-03-26 
 4      |    1       | failed  | 2018-03-27 
 1      |    2       | failed  | 2018-03-24 
 1      |    2       | passed  | 2018-03-25 
 2      |    2       | passed  | 2018-03-26 
 3      |    2       | passed  | 2018-03-27 
 4      |    2       | failed  | 2018-03-27 

在这种情况下,查询应该同时提取 student_id 1 和 2

我试过了,但显然没有用 -

select * 
from table 
where (test_id = 1 and status = 'passed') 
and (test_id = 2 and status = 'passed') 
and (test_id = 3 and status = 'passed') 
and (test_id = 4 and status = 'failed')

【问题讨论】:

  • 假设一旦测试通过,就不会再次尝试,您可以获得每组 test_id 和 student_id 的 max(completed_on),然后只检查这些行。跨度>
  • @clinomaniac 说,接受是一个日期;如果重拍发生在同一日期,则不能保证该日期的最大值是您想要的记录。理想情况下,该表还应该有一个自动递增的主键 - 然后您可以在组内使用其中的最大值
  • 一条记录不能是 test_ID=1 和 test_ID = 2。所以 ands 需要是 or's 然后你需要计算具有 count = 4 分组的唯一测试通过 student_ID 但如果测试 4 进行了两次,第一次失败然后通过...你会得到它而不想要它吗?
  • 不参加考试 4 算不算失败?因此,如果一个人没有 Test_4 记录,但他们通过了 1-3 次...您希望该学生返回吗?

标签: mysql sql tsql


【解决方案1】:

Demo

SELECT count(Z.Test_ID), Z.student_ID 
FROM (SELECT distinct student_ID, test_ID, Status 
      FROM table) Z
WHERE (Z.Status = 'Passed' and Z.test_ID in (1,2,3,4))
   OR (Z.status = 'Failed' and Z.test_ID = 4)
GROUP BY Z.Student_ID
HAVING count(Z.Test_ID)  = 4;

这首先确保我们只有每个学生、状态和 test_ID 的不同记录。 (派生表Z)

然后,我们评估测试 1、2、3、4 中存在多少通过,以及测试 4 存在失败。如果计数不是 4,那么我们知道他们没有通过测试 1- 3 并且未通过 4 或者他们也通过了测试 4。

【讨论】:

    【解决方案2】:

    我并不是说这是快速或最有效的,但它会完成这项工作。确保你的桌子上有正确的索引,

    SELECT s1.student_id
    FROM mytable s1
    JOIN mytable s2 on s1.student_id=s2.student_id and s2.test_id=2 and s2.status='passed'
    JOIN mytable s3 on s1.student_id=s3.student_id and s3.test_id=3 and s3.status='passed'
    WHERE s1.test_id=1
    AND s1.status='passed'
    AND NOT EXISTS (
        SELECT 1
        FROM mytable s4
        WHERE s4.student_id=s1.student_id
        AND s4.test_id=4
        AND s4.status='passed'
    )
    

    【讨论】:

    • 我认为您希望 s3 加入标准 s3.status 而不是 s2。似乎可以正常工作JOIN mytable s3 on s1.student_id=s3.student_id and s3.test_id=3 and s2.status='passed' s/b JOIN mytable s3 on s1.student_id=s3.student_id and s3.test_id=3 and s3.status='passed'
    • 我作弊并创建了一个 rextester,我尝试了所有 3 个答案来反对 :P 我自己没有找到它。 rextester.com/GYXXN38292
    【解决方案3】:

    另一种方法:

    select distinct t1.student_id
    from mytable t1
    inner join
    -- students passed all the 3 tests 
    (select student_id from mytable where  test_id in (1, 2, 3) 
     and status = 'passed' group by student_id having count(distinct test_id) = 3 ) t2
    on t1.test_id = 4 and t1.status = 'failed' and t1.student_id = t2.student_id
    where not exists 
    (select 1 from mytable where student_id = t1.student_id and 
                                 status = 'passed' and test_id = 4)
    

    PS。如果学生通过了考试(例如考试 1)但后来再次参加考试并失败,则该学生将被视为通过。不确定这是否可以接受。

    【讨论】:

    • 好评。成功之后的失败可能会产生不希望的结果。但是测试 4 有问题。如果学生在失败后通过了会发生什么。你得到那个学生,不应该随意使用Rextester来了解我的意思
    【解决方案4】:

    您可以用来满足您的要求的一种方法基本上是制作一个数据透视表。以任何方式对它进行切片,您都可能需要使用子查询,在这里使用 SUM 函数和 CASE 语句,您可以确定每个学生通过了多少次测试。

    然后,在您的外部 WHERE 子句中,您只能选择测试 1 到 3 获得 1 个或多个“通过”结果的行,以及测试 4 获得 0 个“通过”结果的行。

    SQL Fiddle

    SELECT student_id
    FROM (SELECT student_id, 
        SUM(
              CASE WHEN(test_id = 1 AND result = 'passed')
                THEN 1
                ELSE 0
           END) AS "Test1",
        SUM(
              CASE WHEN(test_id = 2 AND result = 'passed')
                THEN 1
                ELSE 0
               END) AS "Test2",
         SUM(
              CASE WHEN(test_id = 3 AND result = 'passed')
                THEN 1
                ELSE 0
               END) AS "Test3",
        SUM(
              CASE WHEN(test_id = 4 AND result = 'passed')
                THEN 1
                ELSE 0
               END) AS "Test4"
        FROM TestResults
        GROUP BY student_id) tr
    WHERE Test1 > 0 AND Test2 > 0 AND Test3 > 0 AND Test4 = 0
    

    使用此技术,您还可以确定学生通过或未通过考试的次数。例如,您可以将 CASE 语句更改为“失败”并返回外部查询中的测试列,以查看学生未通过测试的次数。例如:

    SELECT student_id, Test1Fails
        FROM (SELECT student_id, 
            SUM(
                  CASE WHEN(test_id = 1 AND result = 'failed')
                    THEN 1
                    ELSE 0
               END) AS "Test1Fails"       
            FROM TestResults
            GROUP BY student_id) tr
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-02
      • 2011-05-02
      • 1970-01-01
      • 2011-07-25
      相关资源
      最近更新 更多