我偶尔会遇到这种模式,我没有找到一种非常令人满意的解决方法。
假设我有一个employee
表和一个review
表。每位员工都可以进行多次审核。我想找到所有employee
个至少有一个“好”评论但没有“坏评论”的人。
我还没有弄清楚如何在不知道员工ID的情况下让子选项工作,我还没有想出正确的连接组合来实现这一点。
有没有办法 WITHOUT 存储过程,函数或带数据服务器端?我已经让它与那些合作,但我相信还有另一种方式。
答案 0 :(得分:7)
由于您尚未发布数据库结构,我做了一些假设和简化(关于rating
列,可能是数字而不是字符字段)。相应调整。
select distinct e.EmployeeId, e.Name
from employee e
left join reviews r1 on e.EmployeeId = r1.EmployeeId and r1.rating = 'good'
left join reviews r2 on e.EmployeeId = r2.EmployeeId and r1.rating = 'bad'
where r1.ReviewId is not null --meaning there's at least one
and r2.ReviewId is null --meaning there's no bad review
select e.EmployeeId, max(e.Name) Name
from employee e
left join reviews r on e.EmployeeId = r.EmployeeId
group by e.EmployeeId
having count(case r.rating when 'good' then 1 else null end) > 0
and count(case r.rating when 'bad' then 1 else null end) = 0
这两种解决方案都是SQL ANSI兼容的,这意味着它们都可以使用完全支持SQL ANSI标准的任何RDBMS风格(大多数RDBMS都适用)。
正如@onedaywhen指出的那样,代码在MS Access中不起作用(没有经过测试,我相信他在这方面的专业知识)。
但我有一个说法(这可能会让一些人感到不安):我几乎不认为MS Access是一个RDBMS。我过去曾与它合作过。一旦你继续前进(Oracle,SQL Server,Firebird,PostGreSQL,MySQL,你的名字),你永远不想回来。严重。
答案 1 :(得分:5)
问题 - 基于B中不存在匹配的A侧返回行 - (没有“错误”评论的员工)描述了“反半连接”。有很多种方法可以完成这种查询,至少有5种我在MS Sql 2005及以上版本中发现过。
我知道这个解决方案适用于 MSSQL 2000及以上版本,并且是我在MS Sql 2005和2008中尝试的5种方法中效率最高的。我不确定它是否有效在MySQL中,它应该,因为它反映了一个相当常见的集合操作。
注意,IN
子句使子查询能够访问外部作用域中的employee
表。
SELECT EE.*
FROM employee EE
WHERE
EE.EmpKey IN (
SELECT RR.EmpKey
FROM review RR
WHERE RR.EmpKey = EE.EmpKey
AND RR.ScoreCategory = 'good'
)
AND
EE.EmpKey NOT IN (
SELECT RR.EmpKey
FROM review RR
WHERE RR.EmpKey = EE.EmpKey
AND RR.ScoreCategory = 'bad'
)
答案 2 :(得分:1)
这是可能的。具体的语法取决于您如何存储“好”和“坏”的评论。
假设您在classification
中有review
列,其值为'good'且'bad'。
然后你可以这样做:
SELECT employee.*
FROM employee
JOIN review
ON employee.id=review.employee_id
GROUP BY employee.id
HAVING SUM(IF(classification='good',1,0))>0 -- count up #good reviews, > 0
AND SUM(IF(classification='bad',1,0))=0 -- count up #bad reviews, = 0.
答案 3 :(得分:1)
SELECT ???? FROM employee,review
WHERE employees.id = review.id
GROUP BY employees.id
HAVING SUM(IF(review='good',1,0)) > 1 AND SUM(IF(review='bad',1,0)) = 0