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

时间:2014-05-21 14:37:03

标签: sql join

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

现在,如果我JOIN A JOIN BC,为什么我最终会有重复的行?我曾多次遇到过这个问题,我不明白。它似乎应该产生与JOIN 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,

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

4 个答案:

答案 0 :(得分:22)

当您拥有相关表格时,您通常会有一对多或多对多的关系。因此,当您加入TableB时,TableA中的每条记录都有许多TableB中的记录。这是正常的和预期的。

现在有时你只需要某些列,而且所有记录都是相同的,那么你需要做一些group by或distinct来删除重复项。让我们看一个例子:

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子句中过滤以删除重复项。如何解决这个问题取决于您的业务规则究竟是什么以及数据库的设计方式以及数据库中的数据类型。

答案 1 :(得分:16)

如果其中一个表MSDH对于给定的Id有多行(如果只是{ {1}}列不是主键),然后查询将导致"重复"行。如果表中的Id有多行,则其他列(唯一标识一行)也必须包含在JOIN条件中。

<强>参考

Related Question on MSDN Forum

答案 2 :(得分:1)

这可能听起来像一个非常基本的&#34; DUH&#34;回答,但确保您在合并文件中使用查找的列实际上充满了唯一值!

我今天早些时候注意到,PowerQuery不会给你一个错误(比如在PowerPivot中),并且很乐意让你运行许多合并。这将导致为每个与非唯一值匹配的记录生成多行。

答案 3 :(得分:0)

好的在这个例子中你得到重复,因为你把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