在 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 来连接两个表而不是一个子查询?的主要内容,如果未能解决你的问题,请参考以下文章

sql sever将两个表合起来语法

如何编写一个mysql数据库脚本

如何在 LINQ sql 中将两个表与一个具有不同值的表连接起来?

如何使用 SQL 查询连接两个表? [复制]

SQL - 连接关于相同实体的两个表

MySQL如何在两个字段上连接表