如何连接3个表,其中每个表都有下一个键

时间:2017-01-20 14:51:40

标签: 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 tableB left join tableC on tableC.BId = tableB.id
    group by tableB.id)

as temp
where tableA.id = temp.Aid  

2 个答案:

答案 0 :(得分:3)

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

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中的所有值

答案 1 :(得分:0)

Masoud的良好反应的另一种方法是使用exists作为相关子查询。

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

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

  1. 它不必将所有记录加在一起 需要一个独特的;因此,你不会受到影响 截然不同。

  2. 它可以早日逃脱。一旦找到A的关键值 子查询(B到C加入),它可以停止查看,因此不必将所有B加入到所有A中。

  3. 我们选择" 1"在子查询中,我们不关心我们选择的内容,因为该值不会在任何地方使用。我们只是使用A的着色来(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"

    开始

    你有tableA,(子查询)temp。这是一个CROSS JOIN,意味着A中的所有记录都将连接到(B JOIN C)的所有记录,因此如果A中有1000条记录,临时结果中有1000条记录,那么您将告诉数据库引擎生成结果集中有1000 * 1000条记录;然后被过滤,只包括在temp和A中匹配的记录。引擎可能足够智能以避免交叉连接并优化查询,但我发现它很难维护。所以我会改写为

    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      
    

    查看子查询(临时)

    我们不需要一个小组,因为我们没有聚合。独特的确将我们降到了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并使其成为存在...使用着色我们不会有连接的性能损失,也不会有明显的性能。并且我将左连接切换到内部,因为我们只需要C和B中的记录,所以如果我们将它保留为" LEFT JOIN"我们在B中有空值。这对我们没用。

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

    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