假设我有一张名为考试的表。每行包含:
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');
答案 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