我有一个“会话”表,其中包含以下字段:
int int(11),
user_id int(11),
login_date timestamp,
ip varchar(15)
我想为每个用户选择最后一个 login_date 和最后三个唯一 ip。我怎样才能以优雅的方式做到这一点?
我找到了一个解决方案,但它非常非常非常难看、低效、耗时,并且涉及 mysql 和 bash 脚本的混合。我怎样才能只在 MySQL 中做到这一点?
PS 该表有 cca 430 万行。
我有一个“会话”表,其中包含以下字段:
int int(11),
user_id int(11),
login_date timestamp,
ip varchar(15)
我想为每个用户选择最后一个 login_date 和最后三个唯一 ip。我怎样才能以优雅的方式做到这一点?
我找到了一个解决方案,但它非常非常非常难看、低效、耗时,并且涉及 mysql 和 bash 脚本的混合。我怎样才能只在 MySQL 中做到这一点?
PS 该表有 cca 430 万行。
花了很多时间MYSQL
从SQL 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
你可以这样做:
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,您将拥有最新登录的用户。
这将为您提供每个 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
然后您可以将它们混合在一起,将它们全部放在一起会占用更多资源,但我认为这是可行的。
祝你好运!