选择从未通过考试的用户

时间:2010-09-07 21:37:18

标签: sql

假设我有一张名为考试的表。每行包含:

  

examDate
  用户id
  通过

因此,我们可能会得到以下结果:

  

2010年1月1日,7,假
  2010年1月2日,8,真实   2010年1月3日,7,真实   2010年1月3日,9,假

我想投放一份报告,其中包含从未通过考试的所有用户。在上面的示例中,此查询只应返回userId 9。

我不想做一些非常低效的事情,如:

Select * from exam where passed = 'false' and userId Not In
(Select userId from exam where passed = 'true');

4 个答案:

答案 0 :(得分:3)

您想要从同一个表中找出两个事实:用户未通过测试,同一个用户从未通过测试。所以你想要做的就是把桌子加到自己身上。

因为其中一个是不存在测试,该连接应该是空左连接。您想说选择不存在与连接条件匹配的行的行。

SELECT e0.*
FROM exam AS e0
LEFT JOIN exam AS e1 ON e1.userId=e0.userId AND e1.passed='true'
WHERE e0.passed='false'
AND e1.examDate IS NULL  -- this can be any non-nullable column in e1

虽然它自然取决于您的架构,DBMS和索引,但这样的连接通常比子查询更有效。

答案 1 :(得分:2)

一次通过:

select userId 
from exam 
group by userId
having max(passed) = 'false'

答案 2 :(得分:1)

尝试:

SELECT 
      ExamDate, UserId, Passed 
FROM
      Exam e1
LEFT JOIN
      Exam e2 ON e1.UserId = e2.UserId AND e2.Passed = 'true'
WHERE
     e1.Passed = 'false'
AND 
     e2.UserId IS NULL

在旁注中,我注意到您使用字符来表示真/假值。您可能无法对此进行控制,但始终建议对此列使用Boolean数据类型,因为SQL在将bool值与文本值进行比较时要快得多。查询将包含:Passed = 0或1。

答案 3 :(得分:0)

这是我的解决方案,它100%有效!

SELECT 

    ex1.userId,

    COUNT(ex2.userId) AS countPassed

FROM

    exam AS ex1

LEFT OUTER JOIN exam AS ex2

    ON ex2.userId = ex1.userId AND ex2.passed = 'true'

GROUP BY ex1.userId

HAVING countPassed = 0