【发布时间】:2014-05-19 19:45:45
【问题描述】:
我有表act_detail:
+------+------+--------+
| id | name | action |
+------+------+--------+
| 1 | Tom | eat |
| 2 | Jack | eat |
| 3 | Tom | play |
| 4 | Tom | sleep |
| 5 | Tom | eat |
| 6 | Jack | sleep |
| 7 | Tom | sleep |
| 8 | Tom | eat |
+------+------+--------+
我想获取“吃”的摘要和下一个最近的同名“睡眠”信息:
+------+--------+----------+
| name | eat_id | sleep_id |
+------+--------+----------+
| Tom | 1 | 4 |
| Jack | 2 | 6 |
| Tom | 5 | 7 |
| Tom | 8 | NULL |
+------+--------+----------+
我发现我可以使用下面的 SQL 得到结果:
SELECT
a.name,
a.id AS eat_id,
(SELECT MIN(id) FROM act_detail b WHERE a.name = b.name AND b.id > a.id AND b.action = 'sleep') AS sleep_id
FROM act_detail a
WHERE a.action = 'eat'
ORDER BY a.id;
但是这个 SQL 需要子查询,当需要获取表 b 中的更多列时,需要更多的子查询。有很多记录会很慢。
假设我们可以添加任何索引。
有没有什么有效的方法可以用标准的SQL(可能一个left join,一个临时表,一个group by statement)来解决这个问题?
【问题讨论】:
-
它不仅是一个子查询,还是一个相关的子查询,因此您正在为父查询中的每一行运行该子查询。但实际上并没有办法解决它,因为您的“下一个更高的 sleep_id”要求需要它。
-
什么是“大量记录”?请记住:对计算机来说慢的东西通常对我们来说足够快。对我们来说很多的东西,对电脑来说往往是一点点。
-
似乎您可以在子查询中包含
ORDER BY id和LIMIT 1,然后去掉MIN()。适当的索引当然会有所帮助。 -
@MarcB 我认为接受的答案是一种有效的方法:)