14

我有 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 |
+------+-------+------+

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

我希望得到所有 fid 的答案,因此结果如下所示:

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

5 回答 5

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

在 MySQL 5.0.51 上测试。

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

于 2008-12-16T19:39:56.030 回答
6
SELECT * FROM
        foo LEFT JOIN
        (
        Foo2bar JOIN bar
             ON foo2bar.bid = bar.bid AND zid = 30
        )
        ON foo.fid = foo2bar.fid;

未经测试

于 2008-12-16T19:36:07.083 回答
2

解决它,您可以从您的选择开始。不要包含您最终不想看到的列。

SELECT foo.fid, bar.value

然后我们可以做WHERE子句,可以看到正如你所说的那样。

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

现在棘手的部分是为我们的 FROM 子句连接事物,使用 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
于 2008-12-16T19:43:06.727 回答
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 与 zid 为 30 的两个柱线相关,则可以返回两个值。

于 2008-12-16T19:47:55.373 回答
-1

FWIW,这个问题实际上并不是关于多对多:这可以很简单地作为一个工会来完成。

SQL 中真正的多对多是CROSS JOIN

于 2008-12-16T23:00:29.980 回答