在 MySQL 中,如何编写 SQL 来连接两个表而不是一个子查询?
Posted
技术标签:
【中文标题】在 MySQL 中,如何编写 SQL 来连接两个表而不是一个子查询?【英文标题】:In MySQL how to write SQL to join two tables better than a subquery? 【发布时间】:2014-02-14 17:21:57 【问题描述】:假设我有两个 mysql 表,purchase_log 是所有客户付款的记录,game_log 是所有玩过的游戏的记录。
create table purchase_log (
client_id int,
purchase_date date,
amount int
);
insert into purchase_log (client_id, purchase_date, amount) values (9, '2012-01-01', 10);
insert into purchase_log (client_id, purchase_date, amount) values (10, '2012-01-01', 5);
insert into purchase_log (client_id, purchase_date, amount) values (11, '2012-01-01', 10);
create table game_log (
client_id int,
game_id int,
game_date date
);
insert into game_log (client_id, game_id, game_date) values (9, 110, '2012-12-01');
insert into game_log (client_id, game_id, game_date) values (10, 110, '2012-12-01');
insert into game_log (client_id, game_id, game_date) values (11, 110, '2012-12-01');
insert into game_log (client_id, game_id, game_date) values (11, 110, '2012-12-02');
insert into game_log (client_id, game_id, game_date) values (11, 110, '2012-12-03');
客户平均花费的金额是多少,按月分组,但仅限于玩过游戏的客户?
select avg(amount)
from purchase_log
where client_id in
(select client_id
from game_log
#where...
)
#and...
group by month(purchase_date);
+-------------+
| avg(amount) |
+-------------+
| 8.3333 |
+-------------+
8.3 这个答案是正确的。 ((10+10+5)/3 = 8.3) 但是很多SO文章说join效率更高,所以我改写成join:
select avg(amount)
from purchase_log p
#where...
join game_log g on p.client_id=g.client_id
#and...
group by month(purchase_date);
+-------------+
| avg(amount) |
+-------------+
| 9.0000 |
+-------------+
但是那个9.0的结果是错误的,应该是8.3。连接给出了错误的结果,因为一个客户端玩了多个游戏,这给出了 3 行。
有什么方法可以修复这个连接吗?还是应该回到效率较低的子查询?
【问题讨论】:
【参考方案1】:尝试此查询的另一种方法是:
select avg(amount)
from purchase_log pl
where exits (select 1
from game_log gl
where gl.client_id = pl.client_id
);
为了使其正常工作,您还需要在game_log(client_id)
上建立索引。
您的结果不同,因为 join
乘以行数。在这种情况下,将条件保留在 where
子句中确实更容易。
【讨论】:
以上是关于在 MySQL 中,如何编写 SQL 来连接两个表而不是一个子查询?的主要内容,如果未能解决你的问题,请参考以下文章