在同一张桌子上join两次的最佳方式是什么?

这有点复杂,但我有2个表。 假设结构是这样的:

*Table1* ID PhoneNumber1 PhoneNumber2 *Table2* PhoneNumber SomeOtherField 

这些表可以根据Table1.PhoneNumber1 – > Table2.PhoneNumber或Table1.PhoneNumber2 – > Table2.PhoneNumber进行连接。

现在,我想要得到一个结果集,其中包含PhoneNumber1,与PhoneNumber1,PhoneNumber2和SomeOtherField对应的PhoneNumber2对应的SomeOtherField。

我想到了两种方法来做到这一点 – 无论是两次join表,还是在ON子句中join一个OR。

方法1

 SELECT t1.PhoneNumber1, t1.PhoneNumber2, t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2 FROM Table1 t1 INNER JOIN Table2 t2 ON t2.PhoneNumber = t1.PhoneNumber1 INNER JOIN Table2 t3 ON t3.PhoneNumber = t1.PhoneNumber2 

这似乎工作。

方法2

以某种方式有一个查询,看起来有点像这样 –

 SELECT ... FROM Table1 INNER JOIN Table2 ON Table1.PhoneNumber1 = Table2.PhoneNumber OR Table1.PhoneNumber2 = Table2.PhoneNumber 

我还没有得到这个工作,我不知道是否有办法做到这一点。

什么是完成这个最好的方法? 这两种方式都不是简单或直观的…有没有更直接的方法来做到这一点? 这个要求通常如何实施?

首先,我会尝试重构这些表格,以避免使用电话号码作为自然键。 我不是自然键的粉丝,这是一个很好的例子。 自然键,特别是像电话号码这样的东西,可以改变,并且经常这样。 发生更改时更新您的数据库将是一个巨大的,容易出错的头痛。 *

方法1 ,你描述这是你最好的select。 它看起来有点简洁,由于命名scheme和简短的别名,但…别名是你的朋友,当谈到多次join同一个表或使用子查询等

我只想清理一下:

 SELECT t.PhoneNumber1, t.PhoneNumber2, t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2 FROM Table1 t JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1 JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2 

我做了什么:

  • 没有必要指定INNER – 这是暗示的事实,你没有指定左或右
  • 不要n后缀您的主查找表
  • N后缀的表别名,你会多次使用它明显

* DBA避免更新自然键的麻烦的一种方法是不指定主键和外键约束,这进一步加重了dbdevise差的问题。 我其实经常看到这一点。

除非Phone1或(更可能)phone2可以为空,否则第一个是好的。 在这种情况下,您想使用左连接而不是内连接。

当你有一个有两个电话号码字段的表时,这通常是一个不好的迹象。 通常这意味着你的数据库devise是有缺陷的。

第一种方法是正确的方法,将做你所需要的。 但是,对于内部联接,如果两个电话号码均存在Table2 ,则只会从Table1select行。 您可能需要执行LEFT JOIN以便selectTable1中的所有行。 如果电话号码不匹配,则SomeOtherField将为空。 如果你想确保你至less有一个匹配的电话号码,你可以做WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

第二种方法可能有一个问题:如果Table2具有PhoneNumber1PhoneNumber2会发生什么? 哪一行将被选中? 根据您的数据,外键等,这可能会或可能不会是一个问题。

你可以使用UNION来组合两个连接:

 SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField FROM Table1 JOIN Table2 ON Table1.PhoneNumber1 = Table2.PhoneNumber UNION SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField FROM Table1 JOIN Table2 ON Table1.PhoneNumber2 = Table2.PhoneNumber 

我的问题是显示logging即使没有或只有一个电话号码存在 (完整的地址簿)。 因此,我使用了左边的所有logging的左连接,即使右边没有相应的logging。 对我来说,这在Microsoft Access SQL(他们需要括号!)

 SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3 t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3 FROM ( ( Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber ) LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber ) LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber;