你如何做很多表外连接?

时间:2008-12-16 19:30:31

标签: sql join many-to-many operator-precedence

我有3个表,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 |
+------+-------+------+

我想要的是,“给我一个包含zid为30的所有fid和值的列表”

我期待所有fids的答案,所以结果如下:

+------+--------+
| fid  | value  |
+------+--------+
|    1 |   null |
|    2 |      8 |
|    3 |   null |
|    4 |     42 |
+------+--------+

5 个答案:

答案 0 :(得分:17)

SELECT * FROM foo
  LEFT OUTER JOIN (foo2bar JOIN bar ON (foo2bar.bid = bar.bid AND zid = 30))
  USING (fid);

在MySQL 5.0.51上测试。

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

答案 1 :(得分:6)

SELECT * FROM
        foo LEFT JOIN
        (
        Foo2bar JOIN bar
             ON foo2bar.bid = bar.bid AND zid = 30
        )
        ON foo.fid = foo2bar.fid;

未测试

答案 2 :(得分:2)

解决这个问题,你可以从你的选择开始。不要包含您不希望最终看到的列。

SELECT foo.fid, bar.value

然后我们可以执行WHERE子句,可以看到就像你表达的那样。

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

现在使用LEFT JOIN将各种事物连接在一起是棘手的部分,因为我们希望看到每个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

答案 3 :(得分:2)

如果你没有为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与两个条形码为30的条形相关,则可以返回fid的两个值。

答案 4 :(得分:-1)

FWIW,问题不在于多对多:这可以简单地作为一个联盟来完成。

SQL中真正的多对多是CROSS JOIN