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

时间:2011-05-14 00:33:36

标签: sql oracle

如果我有一个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'

让它返回“John”和“Mary”。关键点是访问该事物所需的权限数量是任意的。

我觉得这应该是显而易见的,但我无法想出一个优雅的解决方案。首选Oracle兼容解决方案。

编辑:

Kosta和JBrooks的解决方案运作良好。下面是Kosta解决方案的修改版本,只有两次攻击指数,而Kosta's的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

4 个答案:

答案 0 :(得分:2)

好的,我明白为什么人们可能会使用Count()来匹配,这可能会有效,但我认为当事情变得复杂时你会遇到麻烦(而且它们总是变得更复杂一些。)

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

  1. 选择有的人 对那件事的许可。
  2. 并且不存在许可 需要那个THING那个 PERSON没有。
  3. 这样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,您很难在这些表中加载足够的数据,以使此语句的运行时间超过十分之一秒 - 尤其是在索引为正在使用。所以在过去我会同意这个表现 - 今天我从不担心表演,除非它跳出来对我说。当你接近这种方式时,维护要少得多。

答案 1 :(得分:1)

使用:

  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确保不允许重复(两个蓝色),因为这将是误报。

答案 2 :(得分:1)

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')

答案 3 :(得分:0)

select distinct person
from permissions p
join things      t on t.permission = p.permission
                  and t.thing      = 'eggplant'

应该这样做。

相关问题