为什么多表连接会产生重复行?

问题描述 投票:0回答:6

假设我有三个表 A、B 和 C。每个表都有两列:一个主键和一些其他数据。它们每个都有相同的行数。如果我在主键上

JOIN
A 和 B,我最终应该得到与其中任何一个相同的行数(而不是 A.rows * B.rows)。

现在,如果我

JOIN
A JOIN B
C
,为什么我最终会得到重复的行?我多次遇到这个问题,但我不明白。看起来它应该产生与
JOIN
ing
A
B
相同的结果,因为它具有相同的行数,但相反,会产生重复项。

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

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 包含一个历史表,其中包含 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,

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

sql join
6个回答
83
投票

当您有相关表时,您通常会存在一对多或多对多关系。因此,当您连接到 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 中有多个记录。

您通常可以通过使用聚合和分组依据、使用不同或通过在 where 子句中进行过滤来删除重复项来解决此问题。如何解决这个问题取决于您的业务规则是什么、您的数据库是如何设计的以及其中包含什么类型的数据。


53
投票

如果表

M
S
D
H
对于给定的
Id
有多于一行(如果只是
Id
列不是主键),则查询将导致“重复”行。如果表中的
Id
有多于一行,则唯一标识一行的其他列也必须包含在 JOIN 条件中。

参考文献

MSDN 论坛上的相关问题


1
投票

好的,在这个例子中,您会得到重复项,因为您将 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

1
投票

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

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


1
投票

确保您的联接查询正确:我遇到这个问题是由于 加入查询问题

   /****** 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

变压器容量.ItemID 这里错了


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.