在这里提出这个问题的道歉,但我对JOIN的理解相当不稳定,几个小时的搞乱并没有把我带到任何地方。这就是我设置的内容和我需要的内容:
我有三个表,分别用于用户,位置和签到。每次用户前往某个位置时,他们都可以在那里办理登机手续。样本签入表将是:
+------------+---------+-------------+---------------------+
| checkin_id | user_id | location_id | timestamp |
+------------+---------+-------------+---------------------+
| 18 | 99 | 1 | 2011-07-10 16:15:59 |
| 14 | 6 | 2 | 2011-07-10 04:49:53 |
| 17 | 6 | 5 | 2011-07-10 16:15:46 |
| 16 | 99 | 7 | 2011-07-10 16:14:00 |
| 19 | 99 | 2 | 2011-07-10 16:16:27 |
+------------+---------+-------------+---------------------+
如您所见,将有多个用户实例和多个位置实例。我需要弄清楚如何,对于签入表中存在的每个用户,找出他们在某处检查的最近时间。例如,在这种情况下,用户99的最近登记位于位置2(登记号19)并且用户6的最近登记位于位置5(登记号码17)。我只想为每个用户提供最新的签到。有没有办法直接从MySQL获得这个?如果是这样,怎么样?
提前感谢您的帮助。 :)
答案 0 :(得分:2)
SELECT *
FROM checkins AS c
JOIN (
SELECT user_id,MAX(`timestamp`) AS `timestamp`
FROM checkins
GROUP BY user_id
) AS x ON (x.user_id = c.user_id AND x.`timestamp`=c.`timestamp`);
编辑:按要求说明:
内部查询:
SELECT user_id,MAX(`timestamp`) AS `timestamp`
FROM checkins
GROUP BY user_id;
单独运行此查询以查看输出,但它会为每个user_id选择最大时间戳值。然后,通过将其插入子选择,我们将结果视为为了JOIN的目的而单独的表
外部查询:
SELECT *
FROM checkins AS c
JOIN (...) AS x ON (x.user_id = c.user_id AND x.`timestamp`=c.`timestamp`);
使用别名 x <将原始表签入与别名 c (为了便于输入)与第一个查询的结果相连接/ strong>即可。通过执行标准连接,只显示在两个表中都有结果的行 - 因此我们有效地使用连接来过滤掉不需要的行。
最终结果是,您将看到与内部查询匹配user_id和MAX(时间戳)的所有行。
答案 1 :(得分:2)
这可能有效:
SELECT * FROM checkins AS a
WHERE a.timestamp >= ALL(
SELECT timestamp
FROM checkins AS b
WHERE b.user_id = a.user_id
);
说明: 对于checkins表中的每一行,我们检查其时间戳是否等于或大于同一用户的checkins表中所有其他行的时间戳。
您可以在此处详细了解任何子查询: http://dev.mysql.com/doc/refman/5.0/en/any-in-some-subqueries.html
答案 2 :(得分:0)
SELECT c.* FROM checkins c ORDER BY timestamp DESC GROUP BY c.user_id
答案 3 :(得分:0)
select c2.* from checkins as c2
inner join (
select c1.user_id, max(c1.`timestamp`) as recent_checkin_timestamp
from checkins as c1 group by c1.user_id
) as r
on r.recent_checkin_timestamp = c2.`timestamp`
and r.user_id = c2.user_id;
这是一个证明它有效的测试:
mysql> create table checkins (
-> checkin_id int unsigned primary key auto_increment,
-> user_id int unsigned not null,
-> location_id int unsigned not null,
-> `timestamp` timestamp not null)
-> engine innodb;
Query OK, 0 rows affected (0.40 sec)
mysql> insert into checkins
-> (checkin_id, user_id, location_id, `timestamp`) values
-> (18, 99, 1, '2011-07-10 16:15:59'),
-> (14, 6, 2, '2011-07-10 04:49:53'),
-> (17, 6, 5, '2011-07-10 16:15:46'),
-> (16, 99, 7, '2011-07-10 16:14:00'),
-> (19, 99, 2, '2011-07-10 16:16:27');
Query OK, 5 rows affected (0.36 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from checkins;
+------------+---------+-------------+---------------------+
| checkin_id | user_id | location_id | timestamp |
+------------+---------+-------------+---------------------+
| 14 | 6 | 2 | 2011-07-10 04:49:53 |
| 16 | 99 | 7 | 2011-07-10 16:14:00 |
| 17 | 6 | 5 | 2011-07-10 16:15:46 |
| 18 | 99 | 1 | 2011-07-10 16:15:59 |
| 19 | 99 | 2 | 2011-07-10 16:16:27 |
+------------+---------+-------------+---------------------+
5 rows in set (0.00 sec)
mysql> select c2.* from checkins as c2
-> inner join (
-> select c1.user_id, max(c1.`timestamp`) as recent_checkin_timestamp
-> from checkins as c1 group by c1.user_id
-> ) as r
-> on r.recent_checkin_timestamp = c2.`timestamp`
-> and r.user_id = c2.user_id;
+------------+---------+-------------+---------------------+
| checkin_id | user_id | location_id | timestamp |
+------------+---------+-------------+---------------------+
| 17 | 6 | 5 | 2011-07-10 16:15:46 |
| 19 | 99 | 2 | 2011-07-10 16:16:27 |
+------------+---------+-------------+---------------------+
2 rows in set (0.00 sec)
BTW:命名列timestamp
是不明智的,因为它是一个保留字。这就是为什么我需要在上面的所有查询中围绕该列名使用反引号。