left join in mysql后如何获取每个寄存器的最高日期?
How to get the highest date for each register after left join in mysql?
我在 mysql 中有两个表(用户和日志)。
USER TABLE
id email name status
-- ------- ------ --------
1 "x@domain.com" "Carlos" 1
2 "c@domain.com" "Marie" 1
3 "k@domain.com" "Jason" 1
LOG TABLE
id time user_id
-- ------- -------
123 "2020-09-07 08:05:03" 1
124 "2020-09-07 08:32:21" 2
125 "2020-09-09 09:01:46" 1
126 "2020-09-07 11:05:03" 3
我想获取所有用户及其最后一次登录。然后,我有这个查询:
SELECT
user.id,
user.name,
user.email,
MAX(log.time) as time
FROM user
LEFT JOIN log on user.id = log.user_id
WHERE user.status_id = 1
GROUP BY user.id
ORDER BY log.time DESC
查询returns所有用户及其日志(如果没有该用户的日志则为null)但该日志不是该用户的最后一个。有人可以帮助我吗?
提前致谢。
如果您使用的是 MySQL 8+,那么 ROW_NUMBER
是一种明智的做法:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY time DESC) rn
FROM log
)
SELECT
u.id,
u.name,
u.email,
t.time
FROM user u
LEFT JOIN cte t ON u.id = t.user_id
WHERE
u.status = 1 AND t.rn = 1
ORDER BY
t.time DESC;
SELECT u.*, l.*
FROM user
JOIN log ON user.id = log.user_id
JOIN ( SELECT user_id, MAX(time) time
FROM log
GROUP BY user_id ) log1 ON log.user_id = log1.user_id AND log.time = log1.time
适用于MySQL5.x
您只需进行很少的更改即可使查询正常工作(除了两个拼写错误 - 额外的逗号和状态与 status_id):
order by
子句没有任何意义,因为结果集没有 log.time
字段,它只有 max(log.time)
,所以你需要排序,不需要使用 CTE 或子查询 - 只要您不想包含来自 log
table:
的额外列
架构(MySQL v5.7)
CREATE TABLE `user` (
`id` INTEGER primary key,
`email` VARCHAR(14),
`name` VARCHAR(8),
`status` INTEGER
);
INSERT INTO `user`
(`id`, `email`, `name`, `status`)
VALUES
('1', 'x@domain.com', 'Carlos', '1'),
('2', 'c@domain.com', 'Marie', '1'),
('3', 'k@domain.com', 'Jason', '1');
CREATE TABLE log (
`id` INTEGER,
`time` VARCHAR(21),
`user_id` INTEGER
);
INSERT INTO log
(`id`, `time`, `user_id`)
VALUES
('123', '2020-09-07 08:05:03', '1'),
('124', '2020-09-07 08:32:21', '2'),
('125', '2020-09-09 09:01:46', '1'),
('126', '2020-09-07 11:05:03', '3');
查询#1
SELECT
user.id,
user.name,
user.email,
MAX(log.time) as time
FROM user
LEFT JOIN log on user.id = log.user_id
WHERE user.status = 1
GROUP BY user.id
ORDER BY max(log.time) DESC;
结果:
| id | name | email | time |
| --- | ------ | ------------ | ------------------- |
| 1 | Carlos | x@domain.com | 2020-09-09 09:01:46 |
| 3 | Jason | k@domain.com | 2020-09-07 11:05:03 |
| 2 | Marie | c@domain.com | 2020-09-07 08:32:21 |
我在 mysql 中有两个表(用户和日志)。
USER TABLE
id email name status
-- ------- ------ --------
1 "x@domain.com" "Carlos" 1
2 "c@domain.com" "Marie" 1
3 "k@domain.com" "Jason" 1
LOG TABLE
id time user_id
-- ------- -------
123 "2020-09-07 08:05:03" 1
124 "2020-09-07 08:32:21" 2
125 "2020-09-09 09:01:46" 1
126 "2020-09-07 11:05:03" 3
我想获取所有用户及其最后一次登录。然后,我有这个查询:
SELECT
user.id,
user.name,
user.email,
MAX(log.time) as time
FROM user
LEFT JOIN log on user.id = log.user_id
WHERE user.status_id = 1
GROUP BY user.id
ORDER BY log.time DESC
查询returns所有用户及其日志(如果没有该用户的日志则为null)但该日志不是该用户的最后一个。有人可以帮助我吗?
提前致谢。
如果您使用的是 MySQL 8+,那么 ROW_NUMBER
是一种明智的做法:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY time DESC) rn
FROM log
)
SELECT
u.id,
u.name,
u.email,
t.time
FROM user u
LEFT JOIN cte t ON u.id = t.user_id
WHERE
u.status = 1 AND t.rn = 1
ORDER BY
t.time DESC;
SELECT u.*, l.*
FROM user
JOIN log ON user.id = log.user_id
JOIN ( SELECT user_id, MAX(time) time
FROM log
GROUP BY user_id ) log1 ON log.user_id = log1.user_id AND log.time = log1.time
适用于MySQL5.x
您只需进行很少的更改即可使查询正常工作(除了两个拼写错误 - 额外的逗号和状态与 status_id):
order by
子句没有任何意义,因为结果集没有 log.time
字段,它只有 max(log.time)
,所以你需要排序,不需要使用 CTE 或子查询 - 只要您不想包含来自 log
table:
架构(MySQL v5.7)
CREATE TABLE `user` (
`id` INTEGER primary key,
`email` VARCHAR(14),
`name` VARCHAR(8),
`status` INTEGER
);
INSERT INTO `user`
(`id`, `email`, `name`, `status`)
VALUES
('1', 'x@domain.com', 'Carlos', '1'),
('2', 'c@domain.com', 'Marie', '1'),
('3', 'k@domain.com', 'Jason', '1');
CREATE TABLE log (
`id` INTEGER,
`time` VARCHAR(21),
`user_id` INTEGER
);
INSERT INTO log
(`id`, `time`, `user_id`)
VALUES
('123', '2020-09-07 08:05:03', '1'),
('124', '2020-09-07 08:32:21', '2'),
('125', '2020-09-09 09:01:46', '1'),
('126', '2020-09-07 11:05:03', '3');
查询#1
SELECT
user.id,
user.name,
user.email,
MAX(log.time) as time
FROM user
LEFT JOIN log on user.id = log.user_id
WHERE user.status = 1
GROUP BY user.id
ORDER BY max(log.time) DESC;
结果:
| id | name | email | time |
| --- | ------ | ------------ | ------------------- |
| 1 | Carlos | x@domain.com | 2020-09-09 09:01:46 |
| 3 | Jason | k@domain.com | 2020-09-07 11:05:03 |
| 2 | Marie | c@domain.com | 2020-09-07 08:32:21 |