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

sir*_*ank 26 sql join

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

现在,如果我JOIN A JOIN BC,为什么我结束了重复的行?我曾多次遇到过这个问题,我不明白.看起来它应该产生与JOINing 相同的结果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
Run Code Online (Sandbox Code Playgroud)

这是表格的模式.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
Run Code Online (Sandbox Code Playgroud)

表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
Run Code Online (Sandbox Code Playgroud)

表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
Run Code Online (Sandbox Code Playgroud)

表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,
Run Code Online (Sandbox Code Playgroud)

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

HLG*_*GEM 29

当您拥有相关表时,您通常会有一对多或多对多的关系.因此,当您加入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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

这些不重复,因为即使在早期字段中存在重复值,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
Run Code Online (Sandbox Code Playgroud)

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

您通常通过使用聚合和分组来修复此问题,方法是使用distinct或在where子句中过滤以删除重复项.如何解决这个问题取决于您的业务规则究竟是什么以及数据库的设计方式以及数据库中的数据类型.


Jos*_*h B 20

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

参考文献:

MSDN论坛相关问题