繁体   English   中英

SQL查询以查找多个条件的匹配项

[英]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()进行匹配,这可能会有效,但我认为当事情变得复杂一点时,你会遇到麻烦(而且它们总是变得复杂一点。)

如果我用英语说这个问题,那就是:

  1. 选择拥有该THING权限的PEOPLE。
  2. 并且不存在PERSON所没有的那种许可所允许的许可。

所以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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM