Mysql 强制内部联接/左联接优先级和组

Mysql 强制内部联接/左联接优先级和组,mysql,join,subquery,mariadb,Mysql,Join,Subquery,Mariadb,我有一大堆表格,比如a,B1,B2,C1,C2 我从A中选择,加入B1,自身加入B2。我也从C1上的A中选择,它本身在C2上连接,我的意思是: SELECT * FROM A JOIN B1 ON A.b1 = B1.id JOIN B2 ON B1.b2 = B2.id LEFT JOIN C1 ON A.c1 = C1.id LEFT JOIN C2 ON C1.c2 = C2.id 如果B分支失败了,我希望整个查询都失败,这是由这些分支连接的 但是如果

我有一大堆表格,比如a,B1,B2,C1,C2

我从A中选择,加入B1,自身加入B2。我也从C1上的A中选择,它本身在C2上连接,我的意思是:

   SELECT *
     FROM A
     JOIN B1 ON A.b1 = B1.id
     JOIN B2 ON B1.b2 = B2.id
LEFT JOIN C1 ON A.c1 = C1.id
LEFT JOIN C2 ON C1.c2 = C2.id
如果B分支失败了,我希望整个查询都失败,这是由这些分支连接的

但是如果
LEFT JOIN C2
失败,我也希望“C”的分支失败(在这种情况下,我不希望来自C1的信息,我希望为null),但是如果C分支失败,我仍然希望整个查询成功

所以我需要一种:

    SELECT *
      FROM A
      JOIN B1 ON A.b1 = B1.id
      JOIN B2 ON B1.b2 = B2.id
 LEFT JOIN (C1 ON A.c1 = C1.id
       JOIN C2 ON C1.c2 = C2.id)
但据我所知,这不是一种现有的语法

因此,我目前正在将其实施为:

   SELECT *
     FROM A
     JOIN B1 ON A.b1 = B1.id
     JOIN B2 ON B1.b2 = B2.id
LEFT JOIN (SELECT *
             FROM C1
             JOIN C2 ON C1.c2 = C2.id) AS C ON A.c1 = C.c1
要么有观点

这就像一个符咒,让我可以明确地表达哪个连接和哪个连接,以及它们的先例,但是写起来很重,读起来很重,也有点冗余

但我是否还错过了另一个干净的解决方案

测试集:

DROP TABLE IF EXISTS A;
CREATE TABLE A (b1 int, c1 int);

DROP TABLE IF EXISTS B1;
CREATE TABLE B1 (id int, b2 int);

DROP TABLE IF EXISTS B2;
CREATE TABLE B2 (id int);

DROP TABLE IF EXISTS C1;
CREATE TABLE C1 (id int, c2 int);

DROP TABLE IF EXISTS C2;
CREATE TABLE C2 (id int);

INSERT INTO C2 VALUES (1), (2), (3); -- To remove to make join fail.
INSERT INTO C1 VALUES (1, 1), (2, 2), (3, 3);

INSERT INTO B2 VALUES (1), (2), (3);
INSERT INTO B1 VALUES (1, 1), (2, 2), (3, 3);

INSERT INTO A VALUES (1, 1), (2, 2), (3, 3);
据我所知

SELECT *
  FROM A
  INNER JOIN (B1,B2) 
     ON  A.b1 = B1.id
     AND C1.b2 = B2.id
  LEFT JOIN (C1,C2) 
     ON  A.c1 = C1.id
     AND C1.c2 = C2.id)
会像预期的那样工作

SELECT ... FROM (t1,t2) WHERE ... is the same as t1 INNER JOIN t2
上面的例子“像”内部连接,事实上我知道它是交叉连接,这有点不同。。。但直到现在我才明白真正的区别是什么,也许有人能告诉我们;)

在此之前,据我所知,obove的示例应该适用于您

SELECT *
  FROM A
  INNER JOIN (B1,B2) 
     ON  A.b1 = B1.id
     AND C1.b2 = B2.id
  LEFT JOIN (C1,C2) 
     ON  A.c1 = C1.id
     AND C1.c2 = C2.id)
会像预期的那样工作

SELECT ... FROM (t1,t2) WHERE ... is the same as t1 INNER JOIN t2
上面的例子“像”内部连接,事实上我知道它是交叉连接,这有点不同。。。但直到现在我才明白真正的区别是什么,也许有人能告诉我们;)


在此之前,示例obove应该适用于您

这是括号连接的正确语法:

SELECT *
  FROM A
  JOIN B1 ON A.b1 = B1.id
  JOIN B2 ON C1.b2 = B2.id
  LEFT JOIN 
   (C1 JOIN C2 ON C1.c2 = C2.id)
  ON A.c1 = C1.id
想想在熟悉的算术语法中如何使用括号。你不会写:

A * B1 * B2 (* C1 * C2)
你会写:

A * B1 * B2 * (C1 * C2)

也就是说,乘法运算符是一个二进制运算符,因此它有两个操作数,一个左操作数和一个右操作数。操作数可以是一个项或括号内的子表达式。但是子表达式必须遵循相同的规则,其中乘法仍然是一个二进制运算符。不必在表达式的左端粘贴二进制运算符。

这是括号连接的正确语法:

SELECT *
  FROM A
  JOIN B1 ON A.b1 = B1.id
  JOIN B2 ON C1.b2 = B2.id
  LEFT JOIN 
   (C1 JOIN C2 ON C1.c2 = C2.id)
  ON A.c1 = C1.id
想想在熟悉的算术语法中如何使用括号。你不会写:

A * B1 * B2 (* C1 * C2)
你会写:

A * B1 * B2 * (C1 * C2)

也就是说,乘法运算符是一个二进制运算符,因此它有两个操作数,一个左操作数和一个右操作数。操作数可以是一个项或括号内的子表达式。但是子表达式必须遵循相同的规则,其中乘法仍然是一个二进制运算符。您不必在表达式的左端粘贴二进制运算符。

我当前的解决方案是创建如下视图:

CREATE OR REPLACE VIEW VC AS
SELECT C1.id AS c1_id, C2.id AS c2_id
  FROM C1
  JOIN C2 ON C1.c2 = C2.id;
并简单地将连接留在其上:

SELECT *
  FROM A
  JOIN B1 ON A.b1 = B1.id
  JOIN B2 ON B1.b2 = B2.id
  LEFT JOIN VC ON VC.c1_id = A.c1;

它使解决方案保持可读性,并且视图可以在其他查询中重用,这很好。

我当前的解决方案是创建一个视图,如:

CREATE OR REPLACE VIEW VC AS
SELECT C1.id AS c1_id, C2.id AS c2_id
  FROM C1
  JOIN C2 ON C1.c2 = C2.id;
并简单地将连接留在其上:

SELECT *
  FROM A
  JOIN B1 ON A.b1 = B1.id
  JOIN B2 ON B1.b2 = B2.id
  LEFT JOIN VC ON VC.c1_id = A.c1;


它保持了解决方案的可读性,并且视图可以在其他查询中重用,这很好。

是的,您可以使用带连接的括号强制执行特定的查询顺序joins@Shadow它在MariaDB 10上出现语法错误,您在另一个实现上测试过吗?是的,可以将圆括号与连接一起使用,以强制执行特定的顺序joins@Shadow它在MariaDB 10上出现语法错误,您在另一个实现上测试过吗?将逗号语法与显式联接混合在一起并不是一个好主意。请解释您的语句,不这样做的原因是什么?逗号样式的联接语法来自SQL-89,仅作为旧语法支持。它没有什么问题,但在某些情况下,将传统语法与SQL-92
JOIN
语法混合使用可能会导致混淆。例如,
从A开始,B.x=C.y和C.z=A.z上的JOIN C会抛出一个错误,因为
JOIN
是在逗号之前计算的,因此在计算连接条件时,它甚至不知道查询中引用了表A。这是可以解决的,但对一些开发人员来说,这会让人困惑,所以最好避免混合语法。好的,谢谢,也许我从来没有发现过,因为我总是使用括号。使用显式连接的逗号语法并不是一个很好的主意。请解释一下你的说法,不这样做的原因是什么?逗号样式的联接语法来自SQL-89,仅作为旧语法支持。它没有什么问题,但在某些情况下,将传统语法与SQL-92
JOIN
语法混合使用可能会导致混淆。例如,
从A开始,B.x=C.y和C.z=A.z上的JOIN C会抛出一个错误,因为
JOIN
是在逗号之前计算的,因此在计算连接条件时,它甚至不知道查询中引用了表A。这是可以解决的,但是对于一些开发人员来说,这会让人困惑,所以最好避免混合语法。好的,谢谢,也许它从来没有出现在我面前,因为我总是在MariaDB服务器10.0.29上使用括号。这是语法错误,我没有找到相关文档。错误是“在A.c1=c1.id上靠近”。将A.c1=c1.id上的
连接条件移动到括号后,因为
A
是在以下外部定义的:`(c1.C2=C2.id上的c1连接C2)在A.c1=c1.id上的c1连接C2)。谢谢,这是正确的,我在回答中修复了它。这是MariaDB服务器10.0.29上的语法错误,我没有找到关于它的文档。错误为“A.c1=c1.id”上的“near”。请将A.c1=c1.id上的
连接条件移动到括号后,因为
A
是在以下外部定义的:`(c1.C2=C2.id上的c1连接C2)A.c1=c1.id上的c1连接C2。谢谢,这是正确的,我已在回答中修复了它。