1

我有一个“会话”表,其中包含以下字段:

int int(11),
user_id int(11),
login_date timestamp,
ip varchar(15)

我想为每个用户选择最后一个 login_date 和最后三个唯一 ip。我怎样才能以优雅的方式做到这一点?

我找到了一个解决方案,但它非常非常非常难看、低效、耗时,并且涉及 mysql 和 bash 脚本的混合。我怎样才能只在 MySQL 中做到这一点?

PS 该表有 cca​​ 430 万行。

一些示例数据:http ://sqlfiddle.com/#!2/e9ddd

4

3 回答 3

3

花了很多时间MYSQLSQL SERVER

我正在处理我的 Query 以获得更好的 Performance

select 
user_id,
max(cast(login_date as datetime)),
group_concat(distinct ip order by login_date desc SEPARATOR  ' , ')
from 
(
SELECT 
  user_id,
  login_date,
  ip,
  CASE user_id 
   WHEN @curType 
    THEN @curRow := @curRow + 1 
    ELSE @curRow := 1 AND @curType := user_id 
  END as sequence
FROM sessions, (SELECT @curRow := 0, @curType := '') r
ORDER BY user_id asc,login_date desc
)t
where sequence<4
group by user_id

SQL 小提琴

于 2013-07-10T09:26:36.170 回答
0

你可以这样做:

SELECT * FROM (
  SELECT 
    user_id
    ,ip, 
    ,login_date
    ,IF(@user_id = SESSION_GRUOPED.user_id, @rownum:=@rownum+1, @rownum:=1 ) as row_id
    ,(@user_id:= SESSION_GRUOPED.user_id) as group_id
  FROM (
    SELECT user_id, ip, max(login_date) login_date FROM SESSION group by user_id, ip order by user_id, login_date desc
  ) SESSION_GRUOPED 
    JOIN  (SELECT @rownum := 0) r
    JOIN  (select @user_id := 0) u
) RESULT
WHERE row_id < 4;

查询的关键是这部分

SELECT user_id, ip, max(login_date) login_date FROM SESSION group by user_id, ip order by user_id, login_date desc

多亏了它,您可以获得每个用户在给定 ip 上最后一次登录的信息。

然后将其包装起来以在组中设置结果编号,然后您只需将结果限制为小于 4 的结果,因为您只需要单个用户的三个结果。

注意:如果您将 row_id < 4 更改为 row_id = 1,您将拥有最新登录的用户。

于 2013-07-10T09:27:19.530 回答
0

这将为您提供每个 user_id 的最后日期

SELECT s1.* FROM sessions s1 
LEFT OUTER JOIN sessions s2
ON s1.user_id = s2.user_id AND s1.login_date < s2.login_date
WHERE s2.user_id IS NULL

这将为您提供用于每个 user_id 的唯一 IP

SELECT user_id, GROUP_CONCAT(DISTINCT(ip)) FROM sessions GROUP BY user_id

然后您可以将它们混合在一起,将它们全部放在一起会占用更多资源,但我认为这是可行的。

祝你好运!

http://sqlfiddle.com/#!2/bb209/71

于 2013-07-10T09:21:07.990 回答