在同一张桌子上坐两次的最好方法是什么?

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

*Table1*
ID
PhoneNumber1
PhoneNumber2


*Table2*
PhoneNumber
SomeOtherField

这些表可以基于 Table1.PhoneNumber1-> Table2.PhoneNumber 或 Table1.PhoneNumber2-> Table2.PhoneNumber 进行联接。

现在,我想得到一个结果集,其中包含 PhoneNumber1、对应于 PhoneNumber1、 PhoneNumber2和对应于 PhoneNumber2的 Some OtherField。

我想到了两种方法来做到这一点-或者在表上连接两次,或者在 ON 子句中使用 OR 连接一次。

方法一:

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

我还没有让这个起作用,我不知道是否有办法做到。

最好的方法是什么?这两种方法似乎都不简单或直观... 有没有更直接的方法来做到这一点?这个要求一般是如何实现的?

244303 次浏览

第一种方法是正确的方法,可以满足您的需要。但是,对于内部连接,只有在 Table2中存在两个电话号码的情况下,才能从 Table1中选择行。您可能希望执行 LEFT JOIN,以便选择来自 Table1的所有行。如果电话号码不匹配,那么 SomeOtherField就是无效的。如果你想确保你至少有一个匹配的电话号码,那么你可以做 WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

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

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

尽管如此,方法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

我所做的:

  • 不需要指定 INNER-它暗示了这样一个事实: 你没有指定向左或向右
  • 不要在主查找表后面加上 n 后缀
  • N-后缀的表别名,您将使用多次,使其显而易见

* DBA 避免更新自然键的一个令人头疼的方法是不指定主键和外键约束,这会进一步加剧数据库设计不良的问题。这种情况我见得多了。

您可以使用 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

第一个是好的,除非 Phone1或者(更可能的是) Phone2可以为空。在这种情况下,您希望使用左联接而不是内联接。

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

我的问题是 显示记录,即使没有或只有一个电话号码存在(完整的通讯录)。因此,我使用了一个 LEFT JOIN,它从左侧获取所有记录,即使右侧不存在对应的记录。对我来说,这在 MicrosoftAccess 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;
SELECT
T1.ID
T1.PhoneNumber1,
T1.PhoneNumber2
T2A.SomeOtherField AS "SomeOtherField of PhoneNumber1",
T2B.SomeOtherField AS "SomeOtherField of PhoneNumber2"
FROM
Table1 T1
LEFT JOIN Table2 T2A ON T1.PhoneNumber1 = T2A.PhoneNumber
LEFT JOIN Table2 T2B ON T1.PhoneNumber2 = T2B.PhoneNumber
WHERE
T1.ID = 'FOO';

LEFT JOINJOIN也返回相同的结果。

enter image description here