现有表 login_log 登录记录,login_time:登录时间, user_id:用户id, login_ip:登录ip, log_id:自增id, project_id:登录站点。

现在需要获取user_id=(1,3,9,20,1000) 内的会员首次登录的详细信息。

请确保在 project_id、user_id、login_time 等字段上有合适的索引。

语法1:

SELECT a.`user_id`, a.`log_id`, a.`login_time`, a.`login_ip`
FROM `login_log ` AS a
WHERE `user_id` IN (1,3,9,20,1000)
AND pic_time = (
SELECT MAX(pic_time)
FROM `login_log ` as b
WHERE a.user_id= b.user_id
)

1、子查询先计算每个 user_id 的最小 login_time。

缺点:

对于每一行外层查询,都会执行一个子查询来计算 MIN(login_time)。如果数据集很大,这会导致大量的子查询计算,可能会比较慢。

语法:2:(8.0以下最优)

SELECT a.`user_id`, a.`log_id`, a.`login_time`, a.`login_ip`
FROM `login_log ` AS a
INNER JOIN (
SELECT `user_id`, MIN(`login_time`) AS `min_login_time`
FROM `login_log `
WHERE `user_id` IN (1,3,9,20,1000)
GROUP BY `user_id`
) AS b
ON a.`user_id` = b.`user_id` AND a.`login_time` = b.`min_login_time` ;

1、子查询先计算每个 user_id 的最小 login_time。

2、使用了JOIN操作,将子查询的结果与主表进行连接。

3、然后将结果与主查询进行连接,通过ON子句匹配 user_id 和 pic_time。

语法3:窗口函数(适用于MySQL 8.0及以上版本)

WITH RankedLogs AS (
SELECT
`user_id`,
`log_id`,
`login_time`,
`login_ip`,
ROW_NUMBER() OVER (PARTITION BY `user_id` ORDER BY `login_time` ASC) AS `rn`
FROM `login_log `
WHERE  `user_id` IN (1,3,9,20,1000)
)
SELECT
`user_id`,
`log_id`,
`login_time`,
`login_ip`
FROM RankedLogs
WHERE `rn` = 1
LIMIT 21;

1、使用窗口函数ROW_NUMBER()为每个ai_entityid分区内的行分配行号,并按pic_time排序。

2、通过行号(rn)筛选出每个ai_entityid分区内pic_time最早的那一行。

3、限制返回的结果集最多为21行。

作者 admin

百度广告效果展示