您是否曾经编写过一个T-SQL查询来连接表本身?典型的例子是一个employee表,该表列出了个人的主管或老板的ID,它引用了同一表中的另一行。这个示例与此完全不同(提示:如果必须这样做,则搜索“递归层次结构”)。我们今天的例子是不同的。
在我们的示例中,我们将脱离以下场景:给定地图上的城市列表,生成一个可以记录任意两个城市之间的距离的表。换句话说,创建一个列表,其中表中的每个值都与其他每个值配对。对于这个练习,我们不打算计算实际的距离,只是创建记录并留下空间让其他人来填充。听起来相当简单。让我们从最简单的例子开始:两点:纽约和旧金山:
我们可以很容易地创建一个简单的三列表,包含以下条目:
但是一个方向上的距离和回程的距离是一样的,所以实际上,我们只需要一行。在删除冗余记录并将芝加哥添加到城市列表后,我们得到如下结果:
如您所见,向城市列表添加一个值后,距离表中需要增加两行。如您所料,第一个表中的第四个城市在第二个表中需要另外三行。第五个城市需要四个,以此类推。增长几乎是指数级的。在100个城市,我们需要4950对城市在距离表中,在1000个城市,我们需要接近50万。实际数字是
{N * (N - 1) / 2}。
是时候自动化了,这是本文的重点。
让我们一共有五个城市,最后两个是新奥尔良和拉斯维加斯。我们可以轻松地构建下面的网格并填充任何适当的块。黑色方块是同城市对(纽约到纽约,或者芝加哥到芝加哥,等等),所以我们不需要担心它们。如果我们可以得到从纽约到旧金山的距离,例如,我们不需要从旧金山到纽约的距离,所以我们也可以消除所有用灰色标记的正方形:
让我们用数字代替我们的城市名称。毕竟,任何像样的数据库设计都会为City表的每一行分配一个唯一的键。
那么我们如何从一个表中创建这么多关系呢?City表与City ID列上自身的内部连接将生成用黑色标记的正方形。但这正是我们不想要的。那么交叉连接呢?
这样就行了,但结果是我们需要的两倍多。记住,一旦我们知道了从芝加哥到拉斯维加斯的距离,我们就不需要记录从拉斯维加斯到芝加哥的距离。我们还剩下几行城市是一样的,比如从新奥尔良到新奥尔良的距离。
将上面结果集中的城市ID列与网格的城市ID轴进行比较,可以看到,我们只寻找城市2的ID大于城市1的ID的对(单元格)。从这里开始,我们有两种选择:继续使用交叉连接并添加WHERE子句,或者回到内部连接并更改ON子句:
结果是一样的。事实上,查询优化器估计的执行计划也是一样的。
整个练习的重点是:内连接不一定总是相等连接,尽管到目前为止这是最常见的情况。当面对独特的查询需求时,跳出固有的思维模式。在这种情况下,在ON子句中简单地用大于代替等于就可以了。