我可以指定连接发生的顺序吗?

发布于 2024-12-08 06:51:54 字数 835 浏览 0 评论 0原文

假设我有三个表,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

但是连接似乎是左关联的(第一个连接发生在第二个连接之前),所以这不会给出来自 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

但是一旦我在查询中有几个这样的关系(实际上我可能有两个或三个嵌套的),我就担心代码复杂性和查询优化器。

除了这个子查询方法之外,还有其他方法可以指定连接顺序吗?

谢谢。

Say I have three tables, A, B and C. Conceptually A (optionally) has one B, and B (always) has one 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

I want to select All records from A as well as their associated records from B and C if present. However, the B and C data must only occur in the result if both B and C are present.

I feel like I want to do:

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

But Joins seem to be left associative (the first join happens before the second join), so this will not give records from A that don't have an entry in C.

AFAICT I must use sub queries, something along the lines of:

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

but once I have a couple of such relationships in a query (in reality I may have two or three nested), I'm worried both about code complexity and about the query optimizer.

Is there a way for me to specify the join order, other than this subquery method?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

記柔刀 2024-12-15 06:51:55

在 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 子句的位置意味着 b 上的 LEFT JOIN 逻辑上最后发生。据我所知,这是标准的(声称这里是 ANSI 规定的 )但我确信如果它在 MySQL 中不起作用,反对票会通知我!

In SQL Server you can do

SELECT *
FROM   a
       LEFT JOIN b
                 INNER JOIN c
                   ON b.c_fk_id = c.c_id
         ON a.id = b.a_fk_id  

The position of the ON clause means that the LEFT JOIN on b logically happens last. As far as I know this is standard (claimed to be ANSI prescribed here) but I'm sure the downvotes will notify me if it doesn't work in MySQL!

蓝颜夕 2024-12-15 06:51:55

编辑:这就是我说话速度比我想象的要快的结果。我之前的解决方案不起作用,因为“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 |
+------+------+------+------+------+

Edit: And that's what I get for talking faster than I think. My previous solution doesn't work because 'c' hasn't been joined yet. Let's try this again.

We can use a WHERE clause to limit the results to only those that match the criteria you're looking for, where C has a valid (IS NOT NULL) or B does not have a value (IS NULL). Like this:

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);

Without WHERE Results:

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

With WHERE Results:

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 |
+------+------+------+------+------+
夜吻♂芭芘 2024-12-15 06:51:55

是的,您可以使用 STRAIGHT_JOIN 来实现此目的。
使用此关键字时,连接将按照您指定的确切顺序发生。

请参阅: http://dev.mysql.com/doc/refman/5.5 /en/join.html

Yes, you use the STRAIGHT_JOIN for this.
When using this keyword the join will occur in the exact order that you specify.

See: http://dev.mysql.com/doc/refman/5.5/en/join.html

北城半夏 2024-12-15 06:51:55

好吧,我还想出了另一个解决方案,为了完整性我将其发布(尽管我实际上使用了马丁的答案)。

使用 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 毫无意义,但事实就是如此。

Well, I thought up another solution as well, and I'm posting it for completeness (Though I'm actually using Martin's answer).

Use a 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

I'm pretty sure every piece I've read about JOINS said that RIGHT JOINs were pointless, but there you are.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文