开发者

Select Users who have never passed an exam

Suppose that I have a table called exam. Each row contains:

examDate

userId

passed

So, we might have the following results:

Ja开发者_如何学Cn 1 2010, 7, false

Jan 2 2010, 8, true

Jan 3 2010, 7, true

Jan 3 2010, 9, false

I want to run a report which includes all users who have NEVER passed the exam. In the above example, only userId 9 should be returned by this query.

I do not want to do something really inefficient like:

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


You want to find out two facts from the same table: a user failed the test, and the same user never passed the test. So what you want to do is join the table to itself.

Because one of those is a non-existence test, that join should be a null-left-join. You want to say select rows where no row exists that matches the join condition.

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

Whilst it will naturally depend on your schema, DBMS and indexing, joins like this are indeed often more efficient than a subquery.


In a single pass:

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


Try:

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

On a side note, I noticed that you are using characters to represent a true/false value. You might have no control over this but it will always be advisable to use the Boolean datatype for this column because SQL is much quicker at comparing bool values to text values. The query would be contain: Passed = 0 or 1 respectively.


here's my solution, it works 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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜