在同一个表上连接两次的最佳方式是什么?

时间:2021-03-28 07:37:18

This is a little complicated, but I have 2 tables. Let's say the structure is something like this:

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

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

The tables can be joined based on Table1.PhoneNumber1 -> Table2.PhoneNumber, or Table1.PhoneNumber2 -> Table2.PhoneNumber.

可以根据表1连接表。PhoneNumber1 - >表二。PhoneNumber或表1。PhoneNumber2 - > Table2.PhoneNumber。

Now, I want to get a resultset that contains PhoneNumber1, SomeOtherField that corresponds to PhoneNumber1, PhoneNumber2, and SomeOtherField that corresponds to PhoneNumber2.

现在,我想要得到一个包含PhoneNumber1、与PhoneNumber1、PhoneNumber2对应的另一个字段以及与PhoneNumber2对应的另一个字段的resultset。

I thought of 2 ways to do this - either by joining on the table twice, or by joining once with an OR in the ON clause.

我想到了两种方法——要么加入表格两次,要么加入一个或在on子句中。

Method 1:

方法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

This seems to work.

这似乎工作。

Method 2:

方法2:

To somehow have a query that looks a bit like this -

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

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

I haven't gotten this to work yet and I'm not sure if there's a way to do it.

我还没有把它付诸实践,我不确定是否有办法。

What's the best way to accomplish this? Neither way seems simple or intuitive... Is there a more straightforward way to do this? How is this requirement generally implemented?

最好的方法是什么?这两种方法似乎都不简单,也不直观……有更直接的方法吗?这个需求是如何实现的?

5 个解决方案

#1


111  

First, I would try and refactor these tables to get away from using phone numbers as natural keys. I am not a fan of natural keys and this is a great example why. Natural keys, especially things like phone numbers, can change and frequently so. Updating your database when that change happens will be a HUGE, error-prone headache. *

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

Method 1 as you describe it is your best bet though. It looks a bit terse due to the naming scheme and the short aliases but... aliasing is your friend when it comes to joining the same table multiple times or using subqueries etc.

方法一,正如你所描述的,这是你最好的选择。由于命名方案和短别名,它看起来有点简洁,但是……当你多次加入同一个表或使用子查询时,别名就是你的朋友。

I would just clean things up a bit:

我要把东西整理一下:

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

What i did:

我所做的:

  • No need to specify INNER - it's implied by the fact that you don't specify LEFT or RIGHT
  • 不需要指定内部——这是由于您没有指定左或右
  • Don't n-suffix your primary lookup table
  • 不要在主查找表后面加上n后缀
  • N-Suffix the table aliases that you will use multiple times to make it obvious
  • n -后缀表别名,您将多次使用它来使其变得明显

*One way DBAs avoid the headaches of updating natural keys is to not specify primary keys and foreign key constraints which further compounds the issues with poor db design. I've actually seen this more often than not.

* dba避免更新自然键所带来的麻烦的一种方法是不指定主键和外键约束,这进一步加剧了糟糕的db设计问题。我经常看到这种情况。

#2


4  

The first is good unless either Phone1 or (more likely) phone2 can be null. In that case you want to use a Left join instead of an inner join.

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

It is usually a bad sign when you have a table with two phone number fields. Usually this means your database design is flawed.

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

#3


2  

The first method is the proper approach and will do what you need. However, with the inner joins, you will only select rows from Table1 if both phone numbers exist in Table2. You may want to do a LEFT JOIN so that all rows from Table1 are selected. If the phone numbers don't match, then the SomeOtherFields would be null. If you want to make sure you have at least one matching phone number you could then do WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

第一个方法是正确的方法,并将做你需要的。但是,通过内部连接,如果表2中存在两个电话号码,则只需要从表1中选择行。您可能希望执行左连接,以便选择表1中的所有行。如果电话号码不匹配,那么其他字段将为空。如果你想确保你有至少一个匹配的电话号码,你可以在t2的地方做。PhoneNumber不是NULL或t3。PhoneNumber不是零

The second method could have a problem: what happens if Table2 has both PhoneNumber1 and PhoneNumber2? Which row will be selected? Depending on your data, foreign keys, etc. this may or may not be a problem.

第二个方法可能有一个问题:如果表2同时拥有PhoneNumber1和PhoneNumber2,会发生什么情况?将选择哪一行?取决于您的数据、外键等等,这可能是问题,也可能不是问题。

#4


2  

You could use UNION to combine two joins:

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

#5


1  

My problem was to display the record even if no or only one phone number exists (full address book). Therefore I used a LEFT JOIN which takes all records from the left, even if no corresponding exists on the right. For me this works in Microsoft Access SQL (they require the parenthesis!)

我的问题是,即使没有或只有一个电话号码(完整地址簿),也要显示记录。因此,我使用了一个左连接,它从左边获取所有记录,即使右边不存在相应的记录。对我来说,这在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;

#1


111  

First, I would try and refactor these tables to get away from using phone numbers as natural keys. I am not a fan of natural keys and this is a great example why. Natural keys, especially things like phone numbers, can change and frequently so. Updating your database when that change happens will be a HUGE, error-prone headache. *

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

Method 1 as you describe it is your best bet though. It looks a bit terse due to the naming scheme and the short aliases but... aliasing is your friend when it comes to joining the same table multiple times or using subqueries etc.

方法一,正如你所描述的,这是你最好的选择。由于命名方案和短别名,它看起来有点简洁,但是……当你多次加入同一个表或使用子查询时,别名就是你的朋友。

I would just clean things up a bit:

我要把东西整理一下:

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

What i did:

我所做的:

  • No need to specify INNER - it's implied by the fact that you don't specify LEFT or RIGHT
  • 不需要指定内部——这是由于您没有指定左或右
  • Don't n-suffix your primary lookup table
  • 不要在主查找表后面加上n后缀
  • N-Suffix the table aliases that you will use multiple times to make it obvious
  • n -后缀表别名,您将多次使用它来使其变得明显

*One way DBAs avoid the headaches of updating natural keys is to not specify primary keys and foreign key constraints which further compounds the issues with poor db design. I've actually seen this more often than not.

* dba避免更新自然键所带来的麻烦的一种方法是不指定主键和外键约束,这进一步加剧了糟糕的db设计问题。我经常看到这种情况。

#2


4  

The first is good unless either Phone1 or (more likely) phone2 can be null. In that case you want to use a Left join instead of an inner join.

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

It is usually a bad sign when you have a table with two phone number fields. Usually this means your database design is flawed.

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

#3


2  

The first method is the proper approach and will do what you need. However, with the inner joins, you will only select rows from Table1 if both phone numbers exist in Table2. You may want to do a LEFT JOIN so that all rows from Table1 are selected. If the phone numbers don't match, then the SomeOtherFields would be null. If you want to make sure you have at least one matching phone number you could then do WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

第一个方法是正确的方法,并将做你需要的。但是,通过内部连接,如果表2中存在两个电话号码,则只需要从表1中选择行。您可能希望执行左连接,以便选择表1中的所有行。如果电话号码不匹配,那么其他字段将为空。如果你想确保你有至少一个匹配的电话号码,你可以在t2的地方做。PhoneNumber不是NULL或t3。PhoneNumber不是零

The second method could have a problem: what happens if Table2 has both PhoneNumber1 and PhoneNumber2? Which row will be selected? Depending on your data, foreign keys, etc. this may or may not be a problem.

第二个方法可能有一个问题:如果表2同时拥有PhoneNumber1和PhoneNumber2,会发生什么情况?将选择哪一行?取决于您的数据、外键等等,这可能是问题,也可能不是问题。

#4


2  

You could use UNION to combine two joins:

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

#5


1  

My problem was to display the record even if no or only one phone number exists (full address book). Therefore I used a LEFT JOIN which takes all records from the left, even if no corresponding exists on the right. For me this works in Microsoft Access SQL (they require the parenthesis!)

我的问题是,即使没有或只有一个电话号码(完整地址簿),也要显示记录。因此,我使用了一个左连接,它从左边获取所有记录,即使右边不存在相应的记录。对我来说,这在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;