【发布时间】:2011-07-21 21:24:03
【问题描述】:
我已经做 SQL 好几年了,在这段时间里,我对连接的想法是等价连接,如
select ... from t1 join t2 on t1.a = t2.b
注意连接是如何基于一个或多个等式的,这里是t1.a = t2.b。不过最近不记得在哪里看到了一个不等价的join(这个词是我自己编的,如果有真名请告诉我),其中join条件至少包含一个不等式,如
select ... from t1 join t2 on t1.a > t2.b
这可以做一些好事,尤其是外连接。让我用一个例子来说明这一点。
让我们考虑一个名为 products 的表,其中包含以下数据:
product year price
----------------------
apple 2009 4
apple 2008 2
apple 2007 5
apple 2006 6
apple 2005 2
banana 2009 9
banana 2008 12
banana 2007 16
banana 2006 15
banana 2005 10
我们想做通常的“给我每个产品最昂贵的一年”,据我所知,这通常是通过对按产品分组的同一个表进行内部连接来完成的,如下所示:
select t1.`name`, t1.`year`, t1.`price`
from products as t1 join
( select `name`, max(`price`) as `max_price` from products group by `name` ) as t2 on t1.`name`=t2.`name` and t1.`price`=t2.`max_price`
所以,在 t2 上,我们得到了每种产品的最高价格,然后我们将这个结果与同一个表连接起来,以获取该列的其余数据(对于平局来说有点棘手)
但是,对于非等价外连接,我们可以这样做:
select t1.`name`, t1.`year`, t1.`price`
from products as t1 left join products as t2 on t1.`name`=t2.`name` and t1.`price` < t2.`price`
where t2.`name` is null
这一次,我们两次加入同一张桌子,其中 t1 的价格低于 t2 的价格。这里的技巧是,因为这是一个左外连接,所以当连接不匹配时,结果连接上的 t2 值将为空,这发生在价格的最大值。
这两个查询产生相同的结果,但我不确定哪一个的性能更好。第一个查询具有昂贵的分组,而第二个查询必须手动检查所有 t1/t2 对以获得结果。不过,使用非等价连接似乎更容易打破平局。
所以,我的问题是:
是否有任何推荐的资源(书籍、网页)更深入地讨论非对等连接,解释你可以用它们做什么(我假设你可以做的不仅仅是在组中获得最大值),以及与其他方法做同样的事情相比,它们的表现如何?
编辑:我知道窗口函数也可用于执行我上面提到的简单示例。我不是在问如何获得表格的最大值。我知道如何做到这一点,我什至提供了两种方法来做到这一点。我想知道我还能用非等价连接做什么。
【问题讨论】:
-
"θ-join" (theta join): en.wikipedia.org/wiki/Relational_algebra
-
通常编写这些查询的最佳方式是使用分析/窗口函数。
-
@ypercube 谢谢你的名字。很棒的评论。
-
不确定:一个你可以在连接上使用 b-tree 索引,另一个你不能。如果表格足够小,或者您需要访问每一行,这无关紧要。
-
@Oscar:想想这个
t1.a > t2.b(将被编入索引)。如果值之间有数千个可能的值,那么使用索引是没有用的,因为没有足够的选择性。如果您采用 max(t1.a) 那么您可以使用顶部值的索引扫描。理论上,两者都应该生成相同的底层查询计划,因为 SQL 是逻辑的而不是过程的,但如果他们这样做了,我会感到惊讶。 explainextended.com 有大量关于此类 API 级别以下内容的文章。
标签: mysql sql sql-server oracle postgresql