两次加入同一张桌子的最佳方法是什么?

fro*_*die 99 sql join

这有点复杂,但我有2张桌子.假设结构是这样的:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField
Run Code Online (Sandbox Code Playgroud)

可以基于Table1.PhoneNumber1 - > Table2.PhoneNumber或Table1.PhoneNumber2 - > Table2.PhoneNumber来连接表.

现在,我想得到一个结果集,其中包含PhoneNumber1,SomeOtherField,它对应于PhoneNumber1,PhoneNumber2和SomeOtherField,对应于PhoneNumber2.

我想到了两种方法 - 通过两次加入表,或者在ON子句中加入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
Run Code Online (Sandbox Code Playgroud)

这似乎有效.

方法2:

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

SELECT ...
FROM Table1
INNER JOIN Table2 
   ON Table1.PhoneNumber1 = Table2.PhoneNumber OR
      Table1.PhoneNumber2 = Table2.PhoneNumber
Run Code Online (Sandbox Code Playgroud)

我还没有得到这个工作,我不确定是否有办法做到这一点.

实现这一目标的最佳方法是什么?这两种方式都不简单或直观......有没有更简单的方法来做到这一点?这个要求一般如何实施?

Pau*_*sik 136

首先,我会尝试重构这些表,以避免使用电话号码作为自然键.我不是自然键的粉丝,这是一个很好的例子.自然键,尤其是电话号码之类的东西,可以随时更改.发生更改时更新数据库将是一个巨大的,容易出错的问题.*

你描述的方法1是你最好的选择.由于命名方案和短别名,它看起来有点简洁,但是......在多次连接同一个表或使用子查询等时,别名是你的朋友.

我会稍微清理一下:

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
Run Code Online (Sandbox Code Playgroud)

我做了什么:

  • 无需指定INNER - 这是因为您没有指定LEFT或RIGHT
  • 不要为主查找表添加n后缀
  • N-Suffix你将多次使用的表别名使其显而易见

*DBA避免更新自然键的麻烦的一种方法是不指定主键和外键约束,这进一步加剧了db设计不佳的问题.我实际上经常看到这个.

  • @volumeone - 我想你可能误解了我答案的最后部分.主键和外键**都是个好主意.避免它们是糟糕的做法,糟糕的设计和简单的坏. (6认同)

Poi*_*nty 5

您可以使用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
Run Code Online (Sandbox Code Playgroud)

  • 我想到了这一点,但我需要将它作为单个非规范化记录返回...... (2认同)

HLG*_*GEM 5

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

当您有一个包含两个电话号码字段的表时,通常这是一个不好的信号。通常,这意味着您的数据库设计存在缺陷。