我有一个查询要实现.
我有2个表:user和login_logs表.
该用户表看起来像这样:
id || first_name || last_name || 电子邮件 || 用户名 || 激活 || 暂停
1 || 约翰|| 丹|| john @ whatever || john1 || 1 || 0 ||
2 || 迈克|| 哈特|| mike @ whatever || mike1 || 1 || 0 ||
等等
该login_logs表看起来像这样:
id || login_datetime || 用户身份
1 || 2011-01-27 23:04:59 || 1
2 || 2010-01-27 23:04:59 || 2
等等
因此login_logs表记录用户何时登录.
现在我想创建一个选择所有非活动用户的查询.非活动用户是:
1)未登录90天的用户
2)从未登录的用户
我做了一个满足第一个条件但不完全正确的查询:
SELECT DISTINCT u.id, u.last_name, u.first_name, u.email,u.username
FROM users u INNER JOIN login_logs l ON l.user_id = u.id
WHERE u.activated = 1 AND u.suspended = 0 AND DATEDIFF(CURDATE(), l.login_datetime) <= 90
ORDER BY u.last_name, u.first_name, u.id
Run Code Online (Sandbox Code Playgroud)
以上查询不正确,因为如果我已经登录很久以前,但最近它也把我视为非活动用户,因为它看到我在很久以前登录.
所以我想解决上面描述的错误并且还满足第二个条件(选择从未登录过的人).
首先,您的查询需要包含所有用户,因此将其转换为LEFT JOIN.
接下来,您的查询需要使用GROUP BY来获取每个用户的MAX登录时间.
第三,不要对列添加日期函数 - 它不会对性能有帮助,而是索引日期列并构造要测试的日期.
SELECT u.id, u.last_name, u.first_name, u.email, u.username
FROM users u
LEFT JOIN login_logs l ON l.user_id = u.id
WHERE u.activated = 1 AND u.suspended = 0
GROUP BY u.id, u.last_name, u.first_name, u.email, u.username
HAVING IFNULL(max(l.login_datetime), 0) <= ADDDATE(CURDATE(), interval -90 day)
ORDER BY u.last_name, u.first_name, u.id
Run Code Online (Sandbox Code Playgroud)
那里的最后一部分IFNULL(max(l.login_datetime), 0)确保如果LEFT JOIN导致login_logs中没有记录(从未登录),它将使用日期0进行测试,这显然是<= 90 days ago; 因此记录(用户)显示.