[英]SQL query to find matches for multiple criteria
如果我有一个PERMISSIONS
表,看起来像这样:
PERSON PERMISSION
------ ----------
Bob red
John red
John blue
Mary red
Mary blue
Mary yellow
和一个看起来像这样的THINGS表:
THING PERMISSION
----- ----------
apple red
eggplant red
eggplant blue
我试图想出一个纯粹的SQL查询,将让我找出什么PERSON
■找访问哪些THING
秒。 基本上,我想要一个看起来像这样的查询:
SELECT person
FROM ... vague handwaving here ...
WHERE thing = 'eggplant'
并让它返回“约翰”和“玛丽”。 关键点是访问该事物所需的权限数量是任意的。
我觉得这应该是显而易见的,但我无法想出一个优雅的解决方案。 Oracle兼容解决方案首选。
编辑:
Kosta和JBrooks的解决方案运作良好。 下面是Kosta解决方案的修改版本,它只能击中索引两次,而不是Kosta的3倍和JBrooks的4倍(尽管我同意JBrooks认为这可能是不必要的优化)。
SELECT p.person, num_permission, COUNT(p.person)
FROM permissions p
INNER JOIN (
SELECT permission,
COUNT(1) OVER (PARTITION BY thing) AS num_permission
FROM things
WHERE thing = 'eggplant'
) t ON t.permission = p.permission
GROUP BY p.person, num_permission
HAVING COUNT(p.person) = num_permission
好吧,我明白为什么人们可能会使用Count()进行匹配,这可能会有效,但我认为当事情变得复杂一点时,你会遇到麻烦(而且它们总是变得复杂一点。)
如果我用英语说这个问题,那就是:
所以SQL将是:
SELECT DISTINCT P.PERSON, T.THING
FROM PERMISSIONS P
INNER JOIN THINGS T
ON P.PERMISSION = T.PERMISSION
WHERE NOT EXISTS
(SELECT 1
FROM THINGS TSUB
WHERE TSUB.THING = T.THING
AND TSUB.PERMISSION NOT IN
(SELECT PSUB.PERMISSION
FROM PERMISSIONS PSUB
WHERE PSUB.PERSON = P.PERSON))
ORDER BY P.PERSON, T.THING
我现在是一个SQL Server人,所以语法可能有点偏,但你明白了。
性能:有人会说这看起来不是最有效的SQL,所以让我现在为自己辩护。 与系统的其余部分相比,权限和用户表通常较小,而今天使用DBMS,您很难在这些表中加载足够的数据,以使此语句的运行时间超过十分之一秒 - 尤其是在索引为正在使用。 所以在过去我会同意这个表现 - 今天我从不担心表演,除非它跳出来对我说。 当你以这种方式接近它时,更少的维护。
使用:
SELECT p.person
FROM PERMISSIONS p
JOIN THINGS t ON t.permission = p.permission
WHERE t.permission IN ('red', 'blue')
GROUP BY p.person
HAVING COUNT(DISTINCT t.permission) = 2
WHERE子句确保仅包含红色和蓝色值。 COUNT DISTINCT
确保不允许重复(两个蓝色),因为这将是误报。
select person
from permissions
where permission in (select permission from things where thing='eggplant')
group by person
having count(person) = (select count(permission) from things where thing='eggplant')
select distinct person
from permissions p
join things t on t.permission = p.permission
and t.thing = 'eggplant'
应该这样做。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.