非等价连接

时间:2011-03-24 06:23:16

标签: mysql sql sql-server oracle postgresql

我已经做了几年SQL,而且在整个过程中,我对连接的想法是等价连接,如

select ... from t1 join t2 on t1.a = t2.b

注意联接是如何基于一个或多个等式,t1.a = t2.b。但是,最近,我不记得在哪里,我看到了一个非等价的连接(我只是把这个术语放了,请告诉我它是否有真实的名称),其中连接条件包含至少一个不相等的,如在

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,我们获得了每个产品的最高价格,然后我们将这个结果与同一个表联系起来,以获得该列的其余数据(对于抢七来说它有点棘手)< / p>

但是,对于非等价的外连接,我们可以这样做:

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值将为null,这对于价格的最大值会发生。

这两个查询都产生相同的结果,但我不确定哪一个表现更好。第一个查询具有昂贵的分组,而第二个查询必须手动检查所有t1 / t2对以获得结果。但是,使用非等价连接似乎更容易打破。

所以,我的问题是:

是否有任何推荐的来源(书籍,网页)更深入地讨论非等价连接,解释你可以用它们做什么(我假设你可以做的不仅仅是在组中获得最大值),以及他们如何反对其他方法做同样的事情?

编辑:我知道窗口函数也可用于执行上面提到的简单示例。我不是问如何获得表的最大值。我知道怎么做,我甚至提供了两种方法来做到这一点。我想知道对于非等价连接我还能做些什么。

2 个答案:

答案 0 :(得分:2)

  

我们想做通常的“给我每个产品最昂贵的一年”,据我所知,通常用内部联接到按产品分组的同一个表,如此

使用窗口函数更容易完成(正如jonealres已经提到的那样)

select name, 
       year, 
       price,
       max(price) over (partition by name) as most_expensive
from products

答案 1 :(得分:0)

我在这里做了类似的事情SQL Query Creating Start and End DatesSQL Server logical grouping most recent time

这种连接与“平等”连接没有什么不同。 on子句只是一个逻辑评估。如果存在索引,则会对索引的where子句进行密切评估。

除此之外,它取决于每个人的想象力。 SQL很丰富,因此可以组合使用。