【问题标题】:Inner JOIN is returning duplicate rows内部 JOIN 正在返回重复的行
【发布时间】:2026-01-05 11:10:01
【问题描述】:

我有以下表结构,并且在每个表中都包含了主键和外键:

CREATE TABLE `Table1` (
`Table1_ID` int(6) ,
`Table2_FK` int(6) ,
 **Other Fields***
) 

CREATE TABLE `Table2` (
`Table2_ID` int(6) ,
`Table3_FK` int(11),
 **Other Fields***
) 
CREATE TABLE `Table3` (
`Table3_ID` int(6) ,
`Table2_FK` int(11),
 **Other Fields***
) 

CREATE TABLE `Table4` (
`Table4_ID` int(6) ,
`Table3_FK` int(11),
 **Other Fields***
) 

CREATE TABLE `Table5` (
`Table5_ID` int(6) ,
`Table4_FK` int(6),
 **Other Fields***
) 

我设置了以下外键:

 ALTER TABLE `Table5`
 ADD CONSTRAINT `table5_ibfk_4` FOREIGN KEY (`Table4_FK `) REFERENCES   `Table4` (`Table4_ID`);

 ALTER TABLE `Table4`
 ADD CONSTRAINT `table4_ibfk_3` FOREIGN KEY (`Table3_FK `) REFERENCES `Table3` (`Table3_ID`);

 ALTER TABLE `Table1`
ADD CONSTRAINT `table1_ibfk_2` FOREIGN KEY (`Table2_FK `) REFERENCES     `Table2` (`Table2_ID `);

 ALTER TABLE `Table2`
 ADD CONSTRAINT `table2_ibfk_1` FOREIGN KEY (`Table3_FK`) REFERENCES `Table3` (`Table3_ID `);

我的问题是当我运行以下 INNER JOIN 查询时:

 SELECT *
 FROM `Table1 `
 INNER JOIN `Table2` ON `Table1`.`Table2_FK` =`Table2`.`Table2_ID` 
 INNER JOIN `Table3` ON `Table2`.`Table3_FK` = `Table3`.`Table3_ID` 
 INNER JOIN `Table4` ON `Table3`.`Table3_ID` = `Table4`.`Table3_FK ` 
 INNER JOIN `Table5` ON `Table4`.`Table4_ID` = `Table5`.`Table4_FK ` 
 WHERE (`Table1`.`Table1_ID ` ='43');

我希望返回两行,因为只有两条 ID 为 43 的记录,如“WHERE”子句中所述。相反,它返回 8 条 ID 为 43 的记录,我认为 INNER Join 只会返回结果为真而不是所有结果。

更新

当前数据如下:

INSERT INTO `Table1` (`Table1_ID `, `OtherData`, `Table2_FK `, `OtherData2`, `Date`) VALUES
(42, 1, 1, 'New', '2015-03-10 17:41:50'),
(43, 1, 1, 'New', '2015-03-10 17:44:35'),
(44, 1, 1, 'New', '2015-03-10 17:50:34'),
(45, 1, 1, 'New', '2015-03-10 17:55:20'),
(46, 1, 1, 'New', '2015-03-10 18:10:47');

INSERT INTO `Table2` (`Table2_ID `, `OtherData3`, `OtherData4 `,     `OtherData5`, `OtherData6`) VALUES
(1, 'blahtype', NULL, 1, '2015-03-13 00:00:00');

INSERT INTO `Table3` (`Table3_ID `, `Table2_FK `, `OtherData6`) VALUES
(1, 1, 'blahname');

INSERT INTO `Table4` (`Table4_ID`, `Table3_FK `, `OtherData6`, `OtherData7`,     `OtherData7`) VALUES
(2, 1, 'blahfieldname', 'blahcont', 'blahtype'),
(3, 1, 'blahfieldname2', 'blahcont', 'blahtype');

INSERT INTO `Table5` (`Table5_ID `, `OtherData`, `Table4_FK`, `OtherData`) VALUES
(1, 'test2', 2, 42),
(2, 'test3', 3, 42),
(3, 'Test4', 2, 43),
(4, 'test5', 3, 43),
(5, 'test6', 2, 44),
(6, 'test7', 3, 44),
(9, 'test8', 2, 78),
(10, 'test9',3, 78);

当前输出为:

 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |2|1| blahfieldname | blahcont | blahtype |1|test2|2|42
 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |2|1| blahfieldname | blahcont | blahtype |3|test3|2|43
 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |2|1| blahfieldname | blahcont | blahtype |5|test4|2|44
 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |2|1| blahfieldname | blahcont | blahtype |9|test5|2|78
 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |3|1| blahfieldname2| blahcont | blahtype |2|test6|3|42
 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |3|1| blahfieldname2| blahcont | blahtype |4|test7|3|43
 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |3|1| blahfieldname2| blahcont | blahtype |6|test8|3|44
 |43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |3|1| blahfieldname2| blahcont | blahtype |10|test9|3|78

预期输出是:

|43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |2|1| blahfieldname | blahcont | blahtype |3|test3|2|43
|43|1|1|New|2015-03-10 17:44:35|1| blahtype |NULL|1|2015-03-13 00:00:00|1|1| blahname |3|1| blahfieldname2| blahcont | blahtype |4|test7|3|43

【问题讨论】:

  • 请表数据,当前结果和想要的结果!
  • 内连接还是左连接?请确保
  • 这是一个错字,它是一个内部连接,我已经编辑了代码来反映这一点。我还包括了请求的数据

标签: mysql sql database join


【解决方案1】:

您说有两条 id 为 43 的记录 - 在 table1 中。但这在 table2, table3 ... table5 中被引用。

最后,您将显示与 table1 中 id 为 43 的这两行数据的每个关系。

table1
ID    name
1     T1-Firstrow
2     T1-Secondrow

table2
ID    FK    name
1     1     T2-Firstrow
2     1     T2-Secondrow
3     2     T2-Thirdrow

如果您从 table1 中选择 where ID = 1,如果您加入 table2,您仍然会得到两行结果。

编辑:

使用问题中的数据更新,选择 id 43:

table1 has 1 row matching
table2 has 1 row matching
table3 has 1 row matching
table4 has 2 rows matching
table5 has 8 rows matching

table5 中有两列名为“otherdata”,但其中一列似乎是 table1 的 FK。如果是这样,请使用:

SELECT *
 FROM `Table1 `
 INNER JOIN `Table2` ON `Table1`.`Table2_FK` =`Table2`.`Table2_ID` 
 INNER JOIN `Table3` ON `Table2`.`Table3_FK` = `Table3`.`Table3_ID` 
 INNER JOIN `Table4` ON `Table3`.`Table3_ID` = `Table4`.`Table3_FK` 
 INNER JOIN `Table5` ON `Table4`.`Table4_ID` = `Table5`.`Table4_FK` AND 
                        `Table5`.`OtherDataFK` = `Table1`.`Table1_ID`
 WHERE (`Table1`.`Table1_ID ` ='43');

【讨论】:

  • 在表 1 中只有 1 行的 id 为 43 但应该返回两个结果,因为在表 4 中有两条记录匹配 43
  • 但是 table5 与 table4 的两行有 8 个关系。如果您正在寻找“2 行结果集”,请跳过与 table5 的连接,中提琴! :)
  • 是的,你可以 - 但现在你使用 FK 加入它(因此有 8 个结果)。您似乎想要的是使用“其他数据”作为指向 table1 的直接链接(虽然我不能肯定地说)。
  • 是的,我将 otherdata 字段作为外键添加到 table1,因为这返回了我想要的。然后我假设这违背了关系数据库的目的,因此我想我会看看我是否可以获得一个 FK 连接来返回我所期望的。
  • 它确实违背了目的,真的。所以你需要考虑设计,而不是想办法绕过设计来获得你所期望的。也许设计很好,但你的期望是错误的。 :)
【解决方案2】:

你说得对,内连接只返回两边都匹配的结果。

但是,我在这里看不到任何主键。假设你只是没有提到它们,并且所有 ForeignKeys 都指向目标表中的 PrimaryKeys,那么我们将 Table2ID 作为主键,Table3 ID 作为主键,Table5 ID 作为主键。您说 Table1 只有两条 ID = 43 的记录。

我假设表 4 有多个记录,其外键等于表 3 中记录的 ID,其 ID 等于表 2 中记录的外键,其 ID 等于表 1 中的外键。

使用您刚刚编辑的数据,

表 1 返回记录 2,即 ID 为 43 的记录。此记录连接到 FK 上的 Table2 1 等于 Table2 中的一条记录。 这条记录与表 3 中的一条记录连接到 Table3。这条记录连接到表 4 中的两条记录,所以现在我们有 2 条记录。这两条记录在表 4 ID = 表 5 FK 上连接到表 5,这两条记录中的每一条都连接到表 5 中的 4 条记录。

这会在结果集中为您提供 8 条记录。

~编辑总共有 8 条记录,你跳到 ID 10 我假设表 5 中有 10 条记录。你的表 2 也缺少它的 FK。

【讨论】:

  • 正确,'TableX_ID' 是每个表中的主键,您的假设是正确的