【发布时间】:2013-11-28 17:53:52
【问题描述】:
当第三个表t3 上存在给定条件时,我想将第二个表t2 左外连接到第一个表t1,该表已连接到第二个表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');
【问题讨论】:
-
添加一些样本和您的预期结果会很有帮助
-
如果不使用子选择,这可能会更快。
-
尝试对两个查询运行解释计划并比较该输出...我认为查询计划应该相同。
-
@Axel。我怎么会不使用子选择?它不会过滤 t1 吗?
-
@user1032531 “过滤器 t1”是什么意思?您使用左连接,因此 t1 中的所有内容都会显示出来。