【问题标题】:Why do multiple-table joins produce duplicate rows?为什么多表连接会产生重复行?
【发布时间】:2014-07-10 06:50:53
【问题描述】:

假设我有三个表 A、B 和 C。每个表都有两列:一个主键和一些其他数据。它们每个都有相同的行数。如果我在主键上JOIN A 和 B,我最终应该得到与其中任何一个相同的行数(而不是 A.rows * B.rows)。

现在,如果我 JOIN A JOIN BC,为什么我会得到重复的行?我曾多次遇到这个问题,但我不明白。看起来它应该产生与JOINing AB 相同的结果,因为它具有相同的行数,但是会产生重复。

产生这样的结果的查询具有以下格式

SELECT *
FROM M
    INNER JOIN S
        on M.mIndex = S.mIndex
    INNER JOIN D
        ON M.platformId LIKE '%' + D.version + '%'
    INNER JOIN H
        ON D.Name = H.Name
        AND D.revision = H.revision

这里是表的架构。 H contains 是一个历史表,其中包含 D 中的所有内容。每个 D 有许多 M 行,每个 M 有一个 S。

表 M

    [mIndex] [int] NOT NULL PRIMARY KEY,
    [platformId] [nvarchar](256) NULL,
    [ip] [nvarchar](64) NULL,
    [complete] [bit] NOT NULL,
    [date] [datetime] NOT NULL,
    [DeployId] [int] NOT NULL PRIMARY KEY REFERENCES D.DeployId,
    [source] [nvarchar](64) NOT NULL PRIMARY KEY

表 S

[order] [int] NOT NULL PRIMARY KEY,
[name] [nvarchar](64) NOT NULL,
[parameters] [nvarchar](256) NOT NULL,
[Finished] [bit] NOT NULL,
[mIndex] [int] NOT NULL PRIMARY KEY,
[mDeployId] [int] NOT NULL PRIMARY KEY,
[Date] [datetime] NULL,
[status] [nvarchar](10) NULL,
[output] [nvarchar](max) NULL,
[config] [nvarchar](64) NOT NULL PRIMARY KEY

表 D

[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[branch] [nvarchar](64) NOT NULL,
[revision] [int] NOT NULL,
[version] [nvarchar](64) NOT NULL,
[path] [nvarchar](256) NOT NULL

表 H

[IdDeploy] [int] IDENTITY(1,1) NOT NULL,
[name] [nvarchar](64) NOT NULL,
[version] [nvarchar](64) NOT NULL,
[path] [nvarchar](max) NOT NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NULL,
[Revision] [nvarchar](64) NULL,

我最初没有发布表格和查询,因为我更感兴趣的是自己了解这个问题并在将来避免它。

【问题讨论】:

  • 您正在运行的完整查询是什么?
  • 这在很大程度上取决于您使用的连接类型。
  • 您可能正在进行笛卡尔连接。维基页面有这种和其他类型的连接的例子 - en.wikipedia.org/wiki/Join_(SQL)#Cross_join
  • @sirdank 如果没有您查询的数据的额外样本,这不是一个有用的示例。
  • @MattThrower 这是故意的。我故意询问连接的机制以便更好地理解它们。我想学钓鱼,而不是饿了就向我要鱼。我将发布表定义并更新示例查询。

标签: sql join


【解决方案1】:

当您有相关的表时,您通常会有一对多或多对多的关系。因此,当您加入 TableB 时,TableA 中的每条记录在 TableB 中都有多个记录。这是正常的,也是意料之中的。

现在有时您只需要某些列并且所有记录都相同,那么您需要进行某种分组或区分以删除重复项。我们来看一个例子:

TableA
Id Field1
1  test
2  another test

TableB
ID Field2 field3
1  Test1  something
1  test1  More something
2  Test2  Anything

所以当你加入他们并选择你得到的所有文件时:

select * 
from tableA a 
join tableb b on a.id = b.id

a.Id a.Field1        b.id   b.field2  b.field3
1    test            1      Test1     something
1    test            1      Test1     More something
2    another test 2  2      Test2     Anything

这些不是重复的,因为 Field3 的值是不同的,即使前面的字段中有重复的值。现在,当您只选择某些列时,相同数量的记录被连接在一起,但由于没有显示具有不同信息的列,它们看起来像是重复的。

select a.Id, a.Field1,  b.field2
from tableA a 
join tableb b on a.id = b.id

a.Id a.Field1       b.field2  
1    test           Test1     
1    test           Test1 
2    another test   Test2

这似乎是重复的,但这不是因为 TableB 中有多个记录。

您通常可以通过使用聚合和分组依据、使用 distinct 或在 where 子句中过滤以删除重复项来解决此问题。你如何解决这个问题取决于你的业务规则是什么,你的数据库是如何设计的,以及里面有什么样的数据。

【讨论】:

  • 我错过了“分组依据”参数,这对我有帮助。谢谢解释
【解决方案2】:

如果MSDH 表之一对于给定的Id 有不止一行(如果只有 Id 列不是主键),那么查询将导致“重复”行。如果表中的Id 有不止一行,则可以唯一标识一行的其他列也必须包含在 JOIN 条件中。

参考文献

Related Question on MSDN Forum

【讨论】:

    【解决方案3】:

    这听起来像是一个非常基本的“DUH”答案,但请确保您用于从合并文件中查找的列实际上充满了唯一值!

    我今天早些时候注意到,PowerQuery 不会向您抛出错误(如在 PowerPivot 中),并且会很高兴地允许您运行多对多合并。这将导致为与非唯一值匹配的每条记录生成多行。

    【讨论】:

      【解决方案4】:

      好的,在这个例子中你得到了重复,因为你将 D 和 S 加入到 M 上。 我假设您应该将 D.id 加入 S.id,如下所示:

      SELECT *
      FROM M
      INNER JOIN S
          on M.Id = S.Id
      INNER JOIN D
          ON S.Id = D.Id
      INNER JOIN H
          ON D.Id = H.Id
      

      【讨论】:

        【解决方案5】:

        在主表 id 上使用 group by 子句我希望它有效 $this->db->group_by('products.id');对于 codeigniter

        【讨论】:

          【解决方案6】:

          确保您的联接查询正确:我遇到此问题是因为 加入查询问题

             /****** Script for command from SSMS  ******/
          SELECT  [TransWorkShopNo]
                ,[TransformerCapacity].[CapacistyPrice]
                ,[TransformerCapacity].[HTCoilPrice]
                ,[TransformerCapacity].[LTCoilReclaimedPrice]
                ,[TransformerCapacity].[LTCoilNewPrice]
          
            FROM [Hi-Lit-Electronics].[dbo].[TransformerData] inner join  TransformerCapacity on [TransformerData].CapacistyID= [TransformerCapacity].CapacistyID 
             inner join  TransformerItem on [TransformerData].ItemID= TransformerCapacity.ItemID
          

          TransformerCapacity.ItemID 这是错误的

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-06-12
            • 2011-03-19
            • 2015-09-11
            • 1970-01-01
            • 1970-01-01
            • 2013-05-01
            • 2015-09-01
            • 2014-10-19
            相关资源
            最近更新 更多