强制INNER JOIN / LEFT JOIN优先级和组

时间:2017-03-15 14:51:46

标签: 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分支失败,我希望整个查询失败,干净地完成那些JOIN。

但是如果LEFT JOIN C2失败,我也希望“C”的分支失败(在这种情况下我不想要来自C1的信息,我想要NULLS),但是我仍然想要整个查询到如果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

使用观点。

它的作用就像一个魅力,允许我明确地表达哪个JOIN与哪个JOIN及其优先级相关,但是它很难写,而且阅读量很大,也有点重复。

但我错过了另一种干净的解决方案吗?

测试集:

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

3 个答案:

答案 0 :(得分:3)

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

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)

即,乘法运算符是二元运算符,因此它有两个操作数,左和右。操作数可以是术语或带括号的子表达式。但是子表达式必须遵循相同的规则,其中乘法仍然是二元运算符。你不能将二元运算符放在表达式的左端。

答案 1 :(得分:0)

据我所知

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

上面的例子工作“喜欢”INNER JOIN,事实上因为我知道它是CROSS JOIN,这略有不同......但直到现在我才知道真正的区别是什么,也许有人可以告诉我们;)

直到那时,示例obove应该适合你

答案 2 :(得分:0)

我目前的解决方案是创建一个类似的视图:

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;

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