需要适当的MySQL查询

时间:2011-07-11 05:26:20

标签: mysql

在这里提出这个问题的道歉,但我对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获得这个?如果是这样,怎么样?

提前感谢您的帮助。 :)

4 个答案:

答案 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`);

编辑:按要求说明:

  1. 内部查询:

    SELECT user_id,MAX(`timestamp`) AS `timestamp`
    FROM checkins
    GROUP BY user_id;
    

    单独运行此查询以查看输出,但它会为每个user_id选择最大时间戳值。然后,通过将其插入子选择,我们将结果视为为了JOIN的目的而单独的表

  2. 外部查询:

    SELECT *
    FROM checkins AS c
    JOIN (...) AS x ON (x.user_id = c.user_id AND x.`timestamp`=c.`timestamp`);
    

    使用别名 x <将原始表签入与别名 c (为了便于输入)与第一个查询的结果相连接/ strong>即可。通过执行标准连接,只显示在两个表中都有结果的行 - 因此我们有效地使用连接来过滤掉不需要的行。

  3. 最终结果是,您将看到与内部查询匹配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是不明智的,因为它是一个保留字。这就是为什么我需要在上面的所有查询中围绕该列名使用反引号。