MySQL Query:3次测试通过,1次失败

时间:2018-03-27 21:26:29

标签: mysql sql tsql

我试图编写一个查询,这将导致已经通过测试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')

4 个答案:

答案 0 :(得分:2)

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。

答案 1 :(得分:1)

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

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'
)

答案 2 :(得分:0)

另一种方法:

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)但后来再次考试并失败,则该学生将被视为通过考试。不确定这是否可以接受。

答案 3 :(得分:0)

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

然后,在你的外部WHERE子句中,你只能选择你有1个或更多个传递的行。测试1到3的结果,0'通过'测试结果4。

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