假设我有三个表,A,B和C.概念上A(可选)有一个B,B(总是)有一个C.
Table A:
a_id
... other stuff
Table B:
a_fk_id (foreign key to A.a_id, unique, primary, not null)
c_fk_id (foreign key to C.c_id, not null)
... other stuff
Table C:
c_id
... other stuff
我想选择A中的所有记录以及B和C中的相关记录(如果存在)。但是,如果B和C都存在,则B和C数据必须仅出现在结果中。
我觉得我想做:
SELECT *
FROM
A
LEFT JOIN B on A.a_id=B.a_fk_id
INNER JOIN C on B.c_fk_id=C.c_id
但是Joins似乎是左关联的(第一次连接发生在第二次连接之前),所以这不会给A中没有C条目的记录。
AFAICT我必须使用子查询,类似于:
SELECT *
FROM
A
LEFT JOIN (
SELECT * FROM B INNER JOIN C ON B.c_fk_id=C.c_id
) as tmp ON A.id = tmp.a_fk_id
但是一旦我在查询中有几个这样的关系(实际上我可能有两个或三个嵌套),我担心代码复杂性和查询优化器。
除了这个子查询方法之外,我有没有办法指定连接顺序?
感谢。
答案 0 :(得分:4)
在SQL Server中,您可以执行
SELECT *
FROM a
LEFT JOIN b
INNER JOIN c
ON b.c_fk_id = c.c_id
ON a.id = b.a_fk_id
ON
子句的位置意味着LEFT JOIN
上的b
在逻辑上最后发生。据我所知这是标准的(claimed to be ANSI prescribed here),但我确信如果在MySQL中不起作用,downvotes会通知我!
答案 1 :(得分:2)
编辑:这就是我说话的速度比我想象的要快。我之前的解决方案不起作用,因为'c'尚未加入。让我们再试一次。
我们可以使用WHERE子句将结果限制为仅匹配您正在查找的条件,其中C具有有效(IS NOT NULL)或B没有值(IS NULL)。像这样:
SELECT *
FROM a
LEFT JOIN b ON (b.a = a.a)
LEFT JOIN c ON (c.b = b.b)
WHERE (c.c IS NOT NULL OR b.b IS NULL);
没有WHERE结果:
mysql> SELECT * FROM a LEFT JOIN b ON (b.a = a.a) LEFT JOIN c ON (c.b = b.b);
+------+------+------+------+------+
| a | a | b | c | b |
+------+------+------+------+------+
| 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 2 | NULL | NULL |
| 2 | 2 | 3 | 2 | 3 |
| 3 | NULL | NULL | NULL | NULL |
| 4 | NULL | NULL | NULL | NULL |
+------+------+------+------+------+
使用WHERE结果:
mysql> SELECT * FROM a LEFT JOIN b ON (b.a = a.a) LEFT JOIN c ON (c.b = b.b) WHERE (c.c IS NOT NULL OR b.b IS NULL);
+------+------+------+------+------+
| a | a | b | c | b |
+------+------+------+------+------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | 2 | 3 | 2 | 3 |
| 3 | NULL | NULL | NULL | NULL |
| 4 | NULL | NULL | NULL | NULL |
+------+------+------+------+------+
答案 2 :(得分:0)
是的,您使用STRAIGHT_JOIN
进行此操作
使用此关键字时,将按照您指定的确切顺序进行连接。
答案 3 :(得分:0)
好吧,我也想到了另一个解决方案,我发布它是为了完整性(虽然我实际上是在使用Martin的答案)。
使用RIGHT JOIN:
SELECT
*
FROM
b
INNER JOIN c ON b.c_fk_id = c.c_id
RIGHT JOIN a ON a.id = b.a_fk_id
我很确定我读到的关于JOINS的每一篇文章都说RIGHT JOIN是毫无意义的,但你就是。