MySQL查询:3个测试通过,1个失败

MySQL查询:3个测试通过,1个失败,mysql,sql,tsql,Mysql,Sql,Tsql,我正在尝试编写一个查询,将通过测试1到3但未通过测试4的学生拉出来 学生可以重考,因此可能会有失败记录,然后是一些考试的通过记录,例如下面的student_id=2 像这样的表格设置- test_id | student_id | status | completed_on --------+------------+---------+------------ 1 | 1 | passed | 2018-03-24 2 | 1

我正在尝试编写一个查询,将通过测试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')

我不是说这是快速或最有效的,但它会做的工作。确保您的表上有正确的索引

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

我不是说这是快速或最有效的,但它会做的工作。确保您的表上有正确的索引

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

这首先要确保每个学生、状态和考试ID都有不同的记录

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

这首先要确保每个学生、状态和考试ID都有不同的记录

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

另一种方法:

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)
注:如果一名学生通过了一项测试(如测试1),但后来又参加了一次测试并失败,则该学生将被视为通过了测试。不确定这是否可以接受。

另一种方法:

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)

注:如果一名学生通过了一项测试(如测试1),但后来又参加了一次测试并失败,则该学生将被视为通过了测试。不确定这是否可以接受。

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

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

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

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

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

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

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

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

假设一旦考试通过,就不会再尝试了,您可以获得每组考试id和学生id的最大值(已完成),然后只对这些行进行检查。@clinomaniac也就是说,接受的是一个日期;如果重拍发生在同一日期,则不能保证该日期的最大值是您想要的记录。理想情况下,该表也会有一个自动递增主键-然后您可以在groupsA记录中使用该主键的最大值test_ID=1和test_ID=2。因此,
需要是
,然后您需要按学生ID对计数=4分组的唯一测试进行计数,但如果测试4进行了两次,第一次失败,然后通过。。。你会明白这一点,但你不想让它正确吗?不参加考试4算不算失败吗?因此,如果一个人没有测试记录,但他们通过了1-3次测试。。。你想让那个学生返回吗?假设一旦考试通过,就不再尝试了,你可以得到每组考试id和学生id的最大值(已完成),然后只对这些行进行检查。@clinomaniac也就是说,接受的是一个日期;如果重拍发生在同一日期,则不能保证该日期的最大值是您想要的记录。理想情况下,该表也会有一个自动递增主键-然后您可以在groupsA记录中使用该主键的最大值test_ID=1和test_ID=2。因此,
需要是
,然后您需要按学生ID对计数=4分组的唯一测试进行计数,但如果测试4进行了两次,第一次失败,然后通过。。。你会明白这一点,但你不想让它正确吗?不参加考试4算不算失败吗?因此,如果一个人没有测试记录,但他们通过了1-3次测试。。。你想让那个学生回来吗?我想你想让s3加入Critierion s3,而不是s2。似乎不这样做
JOIN mytable s3 on s1.student\u id=s3.student\u id和s3.test\u id=3和s2.status='passed'
s/b
JOIN mytable s3 on s1.student\u id=s3.student\u id=3和s3.status='passed'
我作弊并创建了一个rextester,并尝试了所有3个答案:P我自己没有找到它。我认为您希望s3加入到s3的Critieria中,而不是s2。似乎不这样做
JOIN mytable s3 on s1.student\u id=s3.student\u id和s3.test\u id=3和s2.status='passed'
s/b
JOIN mytable s3 on s1.student\u id=s3.student\u id=3和s3.status='passed'
我作弊并创建了一个rextester,并尝试了所有3个答案:P我自己没有找到它。好评论。成功之后的失败可能会产生不期望的结果。但是测试4有一个问题。如果学生在考试不及格后通过了怎么办。你明白了吗