SQL 查询查找多个条件的匹配项
如果我有一个如下所示的 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 的解决方案为 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
If I had a PERMISSIONS
table that looked like this:
PERSON PERMISSION
------ ----------
Bob red
John red
John blue
Mary red
Mary blue
Mary yellow
and a THINGS table that looks like this:
THING PERMISSION
----- ----------
apple red
eggplant red
eggplant blue
I'm trying to come up with a pure SQL query that would let me find out what PERSON
s have access to what THING
s. Basically, I want a query that would look something like:
SELECT person
FROM ... vague handwaving here ...
WHERE thing = 'eggplant'
and have it return "John" and "Mary". The key point being the number of permissions necessary for access to the thing is arbitrary.
I feel like this should be obvious, but I just can't come up with an elegant solution. Oracle compatible solutions preferred.
Edit:
Solutions from Kosta and JBrooks work well. Below is a modified version of Kosta's solution that only hits the indexes twice, as opposed to 3x for Kosta's and 4x for JBrooks's (though I agree with JBrooks that this is probably unnecessary optimization).
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
用途:
WHERE 子句确保仅包含红色和蓝色值。
COUNT DISTINCT
确保不允许重复(两个蓝色),因为这将是误报。Use:
The WHERE clause ensures that only values red and blue are included. The
COUNT DISTINCT
ensures that duplicates (two blue's) are not allowed, as that would be a false positive.好吧,我明白为什么人们可能会使用 Count() 来匹配,这可能会起作用,但我认为当事情变得更复杂时,你会遇到麻烦(而且它们总是变得更复杂。)
如果我用英语说这个问题是:
对该事物的许可。
该事物所需的
人没有。
所以 SQL 应该是:
我现在是 SQL Server 人员,所以语法可能有点不对劲,但你明白了。
性能:有人会说这看起来不像是最高效的 SQL,所以现在让我为自己辩护。与系统的其余部分相比,权限表和用户表通常较小,并且使用当今的 DBMS,您将很难在这些表中加载足够的数据以使该语句的运行时间超过十分之一秒 - 特别是在索引被删除之后在使用中。所以在过去我会同意表演——现在我从不担心表演,除非它突然出现在我面前。当您以这种方式处理时,维护工作就会少得多。
Ok, I get why people might use the Count() to match on and that could work, but I think that you will get into trouble doing this when things get a little more complicated (and they always get a little more complicated.)
If I say this problem in English it is:
permission on that THING.
required for that THING that the
PERSON doesn't have.
So that SQL would be:
I'm a SQL Server guy now so the syntax might be a little off, but you get the idea.
Performance: Someone is going to say that this doesn't look like the most efficient SQL, so let me defend myself now. Permission and user tables are usually on the smaller side compared to the rest of a system and with DBMS today you would be hard pressed to load enough data in these tables to make this statement run longer than a tenth of a second - especially after indexes were in use. So in the past I would have agree about the performance - today I never worry about the performance unless it jumps out at me. So much less maintenance when you approach it this way.
应该这样做。
ought to do it.