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