代码之家  ›  专栏  ›  技术社区  ›  Pyrolistical

如何进行多对多表外部联接?

  •  14
  • Pyrolistical  · 技术社区  · 16 年前

    我有三张桌子,foo,foo2bar和bar。foo2bar是foo和bar之间的多对多映射。内容如下。

    select * from foo
    +------+
    | fid  |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    4 |
    +------+
    
    select * from foo2bar
    +------+------+
    | fid  | bid  |
    +------+------+
    |    1 |    1 |
    |    1 |    2 |
    |    2 |    1 |
    |    2 |    3 |
    |    4 |    4 |
    +------+------+
    
    select * from bar
    +------+-------+------+
    | bid  | value | zid  |
    +------+-------+------+
    |    1 |     2 |   10 |
    |    2 |     4 |   20 |
    |    3 |     8 |   30 |
    |    4 |    42 |   30 |
    +------+-------+------+
    

    我要请求的是,“给我一份所有FID和Zid值为30的列表”

    我希望所有FIDS都有一个答案,所以结果如下:

    +------+--------+
    | fid  | value  |
    +------+--------+
    |    1 |   null |
    |    2 |      8 |
    |    3 |   null |
    |    4 |     42 |
    +------+--------+
    
    5 回复  |  直到 11 年前
        1
  •  17
  •   Bill Karwin    16 年前
    SELECT * FROM foo
      LEFT OUTER JOIN (foo2bar JOIN bar ON (foo2bar.bid = bar.bid AND zid = 30))
      USING (fid);
    

    在MySQL5.0.51上测试。

    这不是子查询,它只使用括号指定联接的优先级。

        2
  •  6
  •   BCS    16 年前
    SELECT * FROM
            foo LEFT JOIN
            (
            Foo2bar JOIN bar
                 ON foo2bar.bid = bar.bid AND zid = 30
            )
            ON foo.fid = foo2bar.fid;
    

    未经测试的

        3
  •  2
  •   Tom H zenazn    16 年前

    如果您没有返回fid=3的行,那么您的服务器就坏了。

    此代码应按我认为的方式执行:

    SELECT
        F.fid,
        SQ.value
    FROM
        dbo.Foo F
    LEFT OUTER JOIN
         (
         SELECT F2B.fid, B.value
         FROM dbo.Bar B
         INNER JOIN dbo.Foo2Bar F2B ON F2B.bid = B.bid WHERE B.zid = 30
         ) SQ ON SQ.fid = F.fid
    

    请记住,如果一个FID与两个zid为30的条相关,则可以返回两个值。

        4
  •  2
  •   Edwin de Koning Umair Baig    11 年前

    你可以从你的选择开始。不要包含最终不想看到的列。

    SELECT foo.fid, bar.value
    

    然后我们可以做WHERE子句,它可以看到正如您所表达的那样。

    SELECT foo.fid, bar.value  
    WHERE bar.zid = 30
    

    现在,使用左联接将FROM子句中的内容连接在一起是一个棘手的部分,因为我们希望看到每个FID,无论是否存在中间匹配:

    SELECT foo.fid, bar.value  
    FROM foo  
    LEFT JOIN foo2bar ON foo.fid = foo2bar.fid  
    LEFT JOIN bar ON foo2bar.bid = bar.bid  
    WHERE bar.zid = 30
    OR bar.zid IS NULL
    
        5
  •  -1
  •   annakata    16 年前

    FWIW,这个问题实际上并不是一个多对多的问题:这可以简单地作为一个联盟来完成。

    SQL中真正的多对多是 CROSS JOIN