繁体   English   中英

联接两个表时向左联接

[英]LEFT OUTER JOIN when joining two tables

我想左外连接的第二表t2至第一表t1当给定的条件上的第三表中存在t3被接合到第二表t2 如果不存在该条件,我仍然希望从第一个表t1返回记录,就像LEFT OUTER JOIN的正常工作方式一样。

我可能已经完全混淆了阅读本文的任何人,因此我编写了两个查询,这些查询返回了我想要的结果。

一个查询比另一个查询更有效率吗? 是否有更有效的查询返回相同的结果?

http://sqlfiddle.com/#!2/bd56e6/8

SELECT *
FROM t1
LEFT OUTER JOIN
(
    SELECT t2.t1_id,t3.fk
    FROM t2
    INNER JOIN t3 ON t3.id=t2.t3_id
    WHERE t3.fk=123
) AS t2 ON t2.t1_id=t1.id

ID  DATA    T1_ID   FK
1   blue    1   123
2   red     (null)  (null)
3   green   (null)  (null)

说明

ID  SELECT_TYPE     TABLE   TYPE    POSSIBLE_KEYS   KEY     KEY_LEN     REF     ROWS    EXTRA
1   PRIMARY     t1  ALL     (null)  (null)  (null)  (null)  3   
1   PRIMARY     <derived2>  ALL     (null)  (null)  (null)  (null)  1   
2   DERIVED     t2  index   PRIMARY     fk_table1_t11_idx   4   (null)  3   Using index
2   DERIVED     t3  ALL     PRIMARY     (null)  (null)  (null)  3   Using where; Using join buffer

http://sqlfiddle.com/#!2/bd56e6/5

SELECT *
FROM t1
LEFT OUTER JOIN
(
    SELECT t2.t1_id,t3.fk
    FROM t2
    INNER JOIN t3 ON t3.id=t2.t3_id 
) AS t2 ON t2.t1_id=t1.id AND t2.fk=123 

ID  DATA    T1_ID   FK
1   blue    1   123
2   red     (null)  (null)
3   green   (null)  (null)

说明

ID  SELECT_TYPE     TABLE   TYPE    POSSIBLE_KEYS   KEY     KEY_LEN     REF     ROWS    EXTRA
1   PRIMARY     t1  ALL     (null)  (null)  (null)  (null)  3   
1   PRIMARY     <derived2>  ALL     (null)  (null)  (null)  (null)  3   
2   DERIVED     t2  index   PRIMARY     fk_table1_t11_idx   4   (null)  3   Using index
2   DERIVED     t3  ALL     PRIMARY     (null)  (null)  (null)  3   Using where; Using join buffer

您将看到以下两个查询产生不同的结果:

http://sqlfiddle.com/#!2/bd56e6/9

SELECT *
FROM t1
LEFT OUTER JOIN t2 ON t2.t1_id=t1.id
LEFT OUTER JOIN t3 ON t3.id=t2.t3_id
WHERE t3.fk=123

ID  DATA    T3_ID   T1_ID   FK
1   blue    1   1   123

http://sqlfiddle.com/#!2/bd56e6/10

SELECT *
FROM t1
LEFT OUTER JOIN t2 ON t2.t1_id=t1.id
LEFT OUTER JOIN t3 ON t3.id=t2.t3_id AND t3.fk=123

ID  DATA    T3_ID   T1_ID   FK
1   blue    1   1   123
2   red     2   2   (null)
2   red     3   2   (null)
3   green   (null)  (null)  (null)

我的架构如下

CREATE  TABLE IF NOT EXISTS t1 (
  id INT NOT NULL ,
  data VARCHAR(45) NULL ,
  PRIMARY KEY (id) )
ENGINE = InnoDB;

CREATE  TABLE IF NOT EXISTS t3 (
  id INT NOT NULL ,
  fk VARCHAR(45) NULL ,
  PRIMARY KEY (id) )
ENGINE = InnoDB;

CREATE  TABLE IF NOT EXISTS t2 (
  t3_id INT NOT NULL ,
  t1_id INT NOT NULL ,
  data VARCHAR(45) NULL ,
  PRIMARY KEY (t3_id) ,
  INDEX fk_table1_t11_idx (t1_id ASC) ,
  CONSTRAINT fk_table1_t3
    FOREIGN KEY (t3_id )
    REFERENCES t3 (id )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT fk_table1_t11
    FOREIGN KEY (t1_id )
    REFERENCES t1 (id )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

INSERT INTO t1(id,data) VALUES (1,'blue');
INSERT INTO t1(id,data) VALUES (2,'red');
INSERT INTO t1(id,data) VALUES (3,'green');

INSERT INTO t3(id,fk) VALUES (1,123);
INSERT INTO t3(id,fk) VALUES (2,321);
INSERT INTO t3(id,fk) VALUES (3,321);

INSERT INTO t2(t1_id,t3_id,data) VALUES (1,1,'dog');
INSERT INTO t2(t1_id,t3_id,data) VALUES (2,2,'Cat');
INSERT INTO t2(t1_id,t3_id,data) VALUES (2,3,'Bird');

玩这样的事情(太晚了,所以我可能有点搞砸了)。 但是,您必须更正ON t3.id=td.t3_id的条件,因为在您的代码和我的代码中我都看不到任何名为td ...的表:

SELECT t1.*,t2.t1_id,t3.fk
FROM t1
LEFT OUTER JOIN t2 ON t2.t1_id=t1.id
LEFT JOIN t3 ON t3.id=td.t3_id -- please update this condition
WHERE t3.fk=123

阅读上面的评论可能是您正在寻找这样的东西:

SELECT t1.*,t2.t1_id,t3.fk
FROM t1
LEFT OUTER JOIN t2 ON t2.t1_id=t1.id
LEFT JOIN t3 ON t3.id=td.t3_id AND t3.fk=123 -- please update this condition

一个查询比另一个查询更有效率吗?

不,它们会生成相同的查询计划,因此它们应该具有相同的性能。 不假设可以从查询缓存或InnoDB缓冲池中获取结果。

是否有更有效的查询返回相同的结果?

好吧,您确实对此提出过疑问,该查询可能会将您推向正确的方向……因为我无法完全确定您是否需要此信息。

SELECT
  t1.id
, t1.data
, IF(t3.fk IS NULL, NULL, t1.id) "t1_id"
, t3.fk
FROM
  t1

LEFT JOIN (
  SELECT 
    t1_id
  FROM 
    t2
  GROUP BY
    t1_id ASC
)
 t2
ON
 t1.id = t2.t1_id

LEFT JOIN 
 t3
ON
 t3.id = t2.t1_id AND t3.fk = '123'

参见演示http://sqlfiddle.com/#!2/bd56e6/136

上面的查询还解决了查询中的重复http://sqlfiddle.com/#!2/bd56e6/173

需要一个较少的派生表,并将类型更改为eq_ref。这将导致更好的性能,因为可以使用更少的内存进行更好的查找。.请注意,无法删除表t1上的全表扫描。

您的要求/问题

当给定条件存在于联接到第二表t2的第三表t3上时,我想将第二表t2外部联接到第一表t1。

但是第一条记录对我来说听起来仍然更像是一种关系(INNER JOIN),因为这是基于条件t3.fk ='123'的匹配记录。

如果不存在该条件,我仍然希望从第一个表t1返回记录,就像LEFT OUTER JOIN的正常工作方式一样。

接下来的记录是表t1中的不匹配项。这使我想知道是否有可能编写一个更好的优化查询。

未完待续...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM