Mysql 如何连接3个表,每个表都有下一行的键

Mysql 如何连接3个表,每个表都有下一行的键,mysql,Mysql,想象一下以下场景: 有3张表A、B和C 表A不了解表B和表C 表B具有表a的外键 表C具有表B的外键 在表B和表C中,可以有多个项目共享相同的外键值 如您所见,C中的项目间接引用到A到B 我想要的是从A中获取在C中引用的所有条目,但在我的结果表中没有来自B或C的任何信息,也没有重复项 这可能吗 我试过这样做,但不知道是否正确: select tableA.* from tableA, (select distinct tableB.AId as Aid from tabl

想象一下以下场景:

有3张表A、B和C

  • 表A不了解表B和表C
  • 表B具有表a的外键
  • 表C具有表B的外键
在表B和表C中,可以有多个项目共享相同的外键值

如您所见,C中的项目间接引用到A到B

我想要的是从A中获取在C中引用的所有条目,但在我的结果表中没有来自B或C的任何信息,也没有重复项

这可能吗

我试过这样做,但不知道是否正确:

select tableA.*
from tableA, 

    (select distinct tableB.AId as Aid
    from tableB left join tableC on tableC.BId = tableB.id
    group by tableB.id)

as temp
where tableA.id = temp.Aid  

我不确定我是否理解正确,但你可以试试这个:

SELECT DISTINCT `A`.`id`, `A`.`value1`, `A`.`value2`  FROM `A`
INNER JOIN `B` ON `B`.`id-a` = `A`.`id`
INNER JOIN `C` ON `C`.`id-b` = `B`.`id`

如果表C上有一个键链接到表B,并且表A上有相应的外键,则返回表A中的所有值。我不确定我是否正确理解它,但您可以尝试以下方法:

SELECT DISTINCT `A`.`id`, `A`.`value1`, `A`.`value2`  FROM `A`
INNER JOIN `B` ON `B`.`id-a` = `A`.`id`
INNER JOIN `C` ON `C`.`id-b` = `B`.`id`

如果表C上有一个键链接到表B,并且表A上有相应的外键,则它将返回表A中的所有值

Masoud良好响应的另一种方法是通过相关子查询使用
exists

下面的子查询以相关方式将B连接到C(注意B.IDA到a.ID,a在子查询之外)

如果我们假设数据库设计良好,那么A将不会有重复的记录,因此我们可以在这里省略distinct,因为我们没有将A连接到其他表。相反,我们只是检查B表中是否存在一条“A”记录,由于内部联接,该记录在C表中必须有一条记录。这对性能有两个好处

  • 它不必将所有的记录连接在一起,然后 必须有一个明确的目标;这样你就不会对表演感兴趣了 不同的

  • 它可以提早逃跑。在中找到a的键值后 子查询(B到C连接),它可以停止查找,因此不必将所有B连接到所有A

  • 我们在子查询中选择“1”,因为我们不在乎选择什么,因为该值不会在任何地方使用。我们只是使用A to(B JOIN C)的颜色来确定A中要显示的内容

    SELECT A.*
    FROM A
    WHERE EXISTS( SELECT 1
                 FROM C
                 INNER JOIN B
                   on C.IDB = B.ID)
                  AND B.IDA = A.ID)
    
    将您尝试过的内容进行回顾:

    select tableA.*
    from tableA, 
    
        (select distinct tableB.AId as Aid
        from tableB left join tableC on tableC.BId = tableB.id
        group by tableB.id)
    
    as temp
    where tableA.id = temp.Aid  
    
    从“FROM”开始

    您有一个表(子查询)temp。这是一个交叉连接,意味着a中的所有记录都将连接到(B JOIN C)的所有记录,因此如果a中有1000条记录,temp结果中有1000条记录,那么您将告诉数据库引擎在结果集中生成1000*1000条记录;该引擎可能足够聪明,可以避免交叉连接并优化查询,但我发现维护起来很混乱。所以我会重写为

    SELECT tableA.*
    FROM tableA 
    INNER JOIN  (SELECT distinct tableB.AId as Aid
                 FROM tableB left join tableC on tableC.BId = tableB.id
                 GROUP BY tableB.id)    as temp
            ON tableA.id = temp.Aid      
    
    查看子查询(temp)

    我们不需要分组,因为我们没有聚合。distinct确实将我们的记录减少到1条,但执行时间有所减少

    因此,我将重写如下:

    SELECT tableA.*
    FROM tableA 
    INNER JOIN  (SELECT distinct tableB.AId as Aid
                 FROM tableB 
                 LEFT JOIN tableC 
                   on tableC.BId = tableB.id) as temp
            ON tableA.id = temp.Aid
    
    然后从整体上看,如果我们将外部查询连接更改为temp并使其成为exists。。。使用着色,我们没有连接的性能影响,也没有明显的效果。我会将左连接切换到一个内部连接,因为我们只需要C和B中的记录,所以如果我们将其作为“左连接”保留,则B中会有null,这对我们没有任何意义

    这让我得到了我最初提供的答案

    SELECT tableA.*
    FROM tableA 
    WHERE EXISTS (SELECT 1
                 FROM tableB 
                 INNER JOIN tableC 
                   on tableC.BId = tableB.id
                  AND tableB.AID = A.ID) as temp
    

    Masoud良好响应的另一种方法是通过相关子查询使用
    exists

    下面的子查询以相关方式将B连接到C(注意B.IDA到a.ID,a在子查询之外)

    如果我们假设数据库设计良好,那么A将不会有重复的记录,因此我们可以在这里省略distinct,因为我们没有将A连接到其他表。相反,我们只是检查B表中是否存在一条“A”记录,由于内部联接,该记录在C表中必须有一条记录。这对性能有两个好处

  • 它不必将所有的记录连接在一起,然后 必须有一个明确的目标;这样你就不会对表演感兴趣了 不同的

  • 它可以提早逃跑。在中找到a的键值后 子查询(B到C连接),它可以停止查找,因此不必将所有B连接到所有A

  • 我们在子查询中选择“1”,因为我们不在乎选择什么,因为该值不会在任何地方使用。我们只是使用A to(B JOIN C)的颜色来确定A中要显示的内容

    SELECT A.*
    FROM A
    WHERE EXISTS( SELECT 1
                 FROM C
                 INNER JOIN B
                   on C.IDB = B.ID)
                  AND B.IDA = A.ID)
    
    将您尝试过的内容进行回顾:

    select tableA.*
    from tableA, 
    
        (select distinct tableB.AId as Aid
        from tableB left join tableC on tableC.BId = tableB.id
        group by tableB.id)
    
    as temp
    where tableA.id = temp.Aid  
    
    从“FROM”开始

    您有一个表(子查询)temp。这是一个交叉连接,意味着a中的所有记录都将连接到(B JOIN C)的所有记录,因此如果a中有1000条记录,temp结果中有1000条记录,那么您将告诉数据库引擎在结果集中生成1000*1000条记录;该引擎可能足够聪明,可以避免交叉连接并优化查询,但我发现维护起来很混乱。所以我会重写为

    SELECT tableA.*
    FROM tableA 
    INNER JOIN  (SELECT distinct tableB.AId as Aid
                 FROM tableB left join tableC on tableC.BId = tableB.id
                 GROUP BY tableB.id)    as temp
            ON tableA.id = temp.Aid      
    
    查看子查询(temp)

    我们不需要分组,因为我们没有聚合。distinct确实将我们的记录减少到1条,但执行时间有所减少

    因此,我将重写如下:

    SELECT tableA.*
    FROM tableA 
    INNER JOIN  (SELECT distinct tableB.AId as Aid
                 FROM tableB 
                 LEFT JOIN tableC 
                   on tableC.BId = tableB.id) as temp
            ON tableA.id = temp.Aid
    
    然后从整体上看,如果我们将外部查询连接更改为temp并使其成为exists。。。使用着色,我们没有连接的性能影响,也没有明显的效果。我会将左连接切换到一个内部连接,因为我们只需要C和B中的记录,所以如果我们将其作为“左连接”保留,则B中会有null,这对我们没有任何意义

    这让我得到了我最初提供的答案

    SELECT tableA.*
    FROM tableA 
    WHERE EXISTS (SELECT 1
                 FROM tableB 
                 INNER JOIN tableC 
                   on tableC.BId = tableB.id
                  AND tableB.AID = A.ID) as temp
    

    如果您为表A、B、C提供一些示例数据,并基于这些示例数据生成您期望的输出,那将是非常棒的