0

我正在处理我试图通过加入命令(不是联合)组合的两组数据。

我不认为我了解加入的基础知识。我使用了完整的外部联接,如下所示:

    Select
      Table1.col1,
      Table1.col2, 
      Table1.date1,
      Table2.col1,
      Table2.col2,
      Table2.date2
   From Table1 full outer join 
        Table2 On Table1.date1 = Table2.date2

最终组合数据集的总行数大于表 1 和表 2 中的行总和。

我试图理解为什么会发生这种情况。

我的印象是 (# rows in CombinedTable) = (# rows in Table1) + (# rows in Table2)。

为什么会出现这种情况?我怎样才能解决这个问题?

4

3 回答 3

1

看一下这个:

TblJob
Name, Surname, Job
John, White, Developer
John, Black, Tester
John, Grey, Manager

TblDrinksPref
Name, Surname, Drink
John, White, Coffee
John, Black, Tea
John, Grey, Orange Juice

SELECT * FROM tbljob j JOIN tbldrinkspref p ON j.name = p.name

John, White, Developer, John, White, Coffee
John, White, Developer, John, Black, Tea
John, White, Developer, John, Grey, Orange Juice
John, Black, Tester, John, White, Coffee
John, Black, Tester, John, Black, Tea
John, Black, Tester, John, Grey, Orange Juice
John, Grey, Manager, John, White, Coffee
John, Grey, Manager, John, Black, Tea
John, Grey, Manager, John, Grey, Orange Juice

通过只加入名字,每个表中的每一行都匹配另一个。每个表中的 3 行导致 3x3 表输出;超过行的总和。您将从联接中获得的最多行数是进入联接的行数的乘积。我们称之为笛卡尔积,它通常表明您的 SQL 连接中存在错误。任何连接都可以做到这一点,而不仅仅是外部连接。存在一个连接(称为 CROSS JOIN),其唯一目的是产生一个完美的笛卡尔积的输出,因为有时我们确实想要这样做,但大多数情况下它表明存在问题

你能为这个做什么?通过使您的连接条件更好/更准确,不要将行连接到不相关的行:

SELECT * 
FROM tbljob j JOIN tbldrinkspref p 
ON j.name = p.name 
  --the last name is vital to associate rows correctly in this case
  AND j.surname = p.surname

如果您编写了一个大型 SQL,并且意外地重复了某些行,则意味着您的一个连接有问题。将它们全部注释回第一个表,并注释选择块,然后在添加连接时继续重新运行 sql。当您看到行数意外增加时,这可能是失败,但请注意连接可能会导致行也会消失,并且您可能会遇到这样一种情况:添加连接可能会导致一半的行消失,因为它们与连接谓词不匹配,而另一半的行会因连接错误而加倍。在评估添加表后行数应该如何变化时,您必须牢记您要连接的数据,而不是实际变化的情况

于 2020-02-23T08:02:32.570 回答
1

您将获得 N 个示例和图表,在查看这些示例和图表之前,您应该对连接有所了解,我假设您使用的是 MS Sql。

全外连接返回一个包含左右表行的结果集,所以如果第一个表有 3 行,第二个表有 5 行,则不一定只有 8 行。它还取决于这两个表之间如何使用外键值。

如果第二个表中的值未与第一个表列值映射,则这些值返回为 null。

正如@Caius Jard 所提到的,返回值会根据映射的值增加。希望它对你有点帮助。

PS Full join 和 Full Outer join 是一样的!

于 2020-02-23T08:08:39.817 回答
0

考虑两个具有 m 行的表 A 和具有 n 行的 B 以及如下查询:

select count(*)
from a full join
     b
     on <some condition>;

此行可以返回(几乎)介于greatest(n, m)和之间的任何数字n * m

greatest(n, m)如果条件始终是 1 对 1(例如在 ids 上),它将返回。

n + m如果条件始终评估为 FALSE ,它将返回。

n * m如果条件始终评估为 TRUE ,它将返回。

它可以返回几乎任何中间的数字,除了少数例外(例如,在许多情况下,很难获得n * m - 1行)。

相比之下,anINNER JOIN可以在0n * m行之间返回。

另一方面,UNION ALL总是准确地返回两个表中行的总和,所以你可能会混淆UNION ALLFULL JOIN.

于 2020-02-23T13:16:14.760 回答