首页 > 试题广场 >

牛客每个人最近的登录日期(二)

[编程题]牛客每个人最近的登录日期(二)
  • 热度指数:163700 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
牛客每天有很多人登录,请你统计一下牛客每个用户最近登录是哪一天,用的是什么设备.
有一个登录(login)记录表,简况如下:
id user_id client_id date
1
2
3
4
2
3
2
3
1
2
2
2
2020-10-12
2020-10-12
2020-10-13
2020-10-13

第1行表示user_id为2的用户在2020-10-12使用了客户端id为1的设备登录了牛客网
。。。
第4行表示user_id为3的用户在2020-10-13使用了客户端id为2的设备登录了牛客网

还有一个用户(user)表,简况如下:

id name
1
2
3
tm
fh
wangchao

还有一个客户端(client)表,简况如下:
id name
1 pc
2 ios
3 anroid
4 h5
请你写出一个sql语句查询每个用户最近一天登录的日子,用户的名字,以及用户用的设备的名字,并且查询结果按照user的name升序排序,上面的例子查询结果如下:
u_n c_n date
fh ios 2020-10-13
wangchao ios 2020-10-13
查询结果表明:
fh最近的登录日期在2020-10-13,而且是使用ios登录的
wangchao最近的登录日期也是2020-10-13,而且是使用ios登录的

示例1

输入

drop table if exists login;
drop table if exists user;
drop table if exists client;
CREATE TABLE `login` (
`id` int(4) NOT NULL,
`user_id` int(4) NOT NULL,
`client_id` int(4) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`));

CREATE TABLE `user` (
`id` int(4) NOT NULL,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`));

CREATE TABLE `client` (
`id` int(4) NOT NULL,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`));

INSERT INTO login VALUES
(1,2,1,'2020-10-12'),
(2,3,2,'2020-10-12'),
(3,2,2,'2020-10-13'),
(4,3,2,'2020-10-13');

INSERT INTO user VALUES
(1,'tm'),
(2,'fh'),
(3,'wangchao');

INSERT INTO client VALUES
(1,'pc'),
(2,'ios'),
(3,'anroid'),
(4,'h5');

输出

fh|ios|2020-10-13
wangchao|ios|2020-10-13
开窗
select u_n,c_n,z.date
from (select a.id,a.name u_n,c.name c_n,a.date,rank()over(partition by a.name order by a.date desc) rt
from (select l.id,u.name,l.client_id,l.date
from login l left join user u 
on l.user_id=u.id) a left join client c on a.client_id=c.id) z
where z.rt=1
order by u_n
发表于 2022-07-20 14:57:56 回复(0)
with demo as
(select
    *,
    dense_rank() over(partition by user_id order by date desc) as rnk
from
    login)

    
select b.name as u_n,c.name as c_n,a.date from demo a,user b,client c

where rnk = 1
and a.user_id = b.id
and a.client_id = c.id
order by b.name

发表于 2022-04-25 00:50:00 回复(0)
select u.name as u_n,c.name as c_n,max(l.date) as d from login l,user u,client c
where l.user_id = u.id
and l.client_id = c.id
group by l.user_id
order by u.name
发表于 2020-09-23 09:00:32 回复(0)
QCA头像 QCA
看见分组就一定要用group by吗 太僵硬了吧
给个高效的方法吧
select u.name,c.name,l1.date
from login l1,user u,client c
where l1.date=(select max(l2.date) from login l2 where l1.user_id=l2.user_id)
and l1.user_id=u.id
and l1.client_id=c.id
order by u.name
其实有更一般的就是加rank列,想要什么取什么


编辑于 2020-09-22 21:51:52 回复(18)

两种思路

使用where子句以及in语句,注意到可以取数组(a,b)in某个查询结果中

select u.name as u_n, c.name as c_n, l.date as d
from login as l
inner join user as u
on l.user_id=u.id
inner join client as c
on l.client_id=c.id
where (l.user_id, l.date) in (
    select user_id, max(date) 
    from login 
    group by user_id
)
order by u.name asc

使用内连接,其实思想与where子句一样

select u.name as u_n, c.name as c_n, l.date as d
from login as l
inner join user as u
on l.user_id=u.id
inner join client as c
on l.client_id=c.id
inner join (
    select user_id, max(date)  as date
    from login 
    group by user_id
) a
on l.user_id=a.user_id
and l.date=a.date
order by u.name asc

注意:错误解答,错误使用group by,select只能包含group by后的项与聚合函数

select u.name as u_n, c.name as c_n, max(l.date) as d
from login as l
inner join user as u
on l.user_id=u.id
inner join client as c
on l.client_id=c.id
group by u.name
order by u.name asc
发表于 2020-11-12 11:11:00 回复(8)
先根据用户分组,查出每个用户登录的最新日期(一):
select user_id,max(date) from login group by login.user_id ;
查找出来的应该这样的


然后查找出所有用户的名字,所有的登录设备,所有的登录日期(二):
select user.name as u_n, client.name as c_n,
login.date
from login 
join user on login.user_id=user.id
join client on login.client_id=client.id
查找的结果应该是:
那么再根据用户id和最新的登录日期(一),可以在所有的数据(二)里面,从而确定唯一一组数据,最后再按照名字排序(三)
select user.name as u_n, client.name as c_n,
login.date
from login 
join user on login.user_id=user.id
join client on login.client_id=client.id
where (login.user_id,login.date) in
(select user_id,max(date) from login group by login.user_id )
order by user.name;




编辑于 2020-09-11 16:26:27 回复(21)
select new.u_n,new.c_n,new.d from 
(
select login.user_id,user.`name` as u_n,client.`name` as c_n,login.date,
(max(login.date) over(PARTITION by login.user_id)) as d
from login,user,client
where login.user_id=user.id and login.client_id=client.id
) as new
where new.date=new.d
order by new.u_n asc
开窗函数分组求最大时间,然后用子查询筛选。

好多答案的group by,都有问题,自己用select *,max(1.date)看下,user_id和client_id和最新date对不上。

发表于 2020-09-03 17:39:33 回复(5)

窗口函数真好用😊

select u.name as u_n, c.name as c_n, temp.date
from (
         select user_id,
                client_id,
                date,
                row_number() over (partition by user_id order by date desc) as date2
         from login
     ) as temp
left join client as c on c.id = temp.client_id
left join user u on temp.user_id = u.id
where temp.date2 = 1
order by u.name
发表于 2021-04-19 16:55:53 回复(2)
-- 考查知识点:表连接,对字符串排序;GROUP BY 
SELECT u.name AS u_n, c.name AS c_n, MAX(l.date) AS date
  FROM login l LEFT JOIN user u ON l.user_id = u.id
               LEFT JOIN client c ON l.client_id = c.id
  GROUP BY u.name 
  ORDER BY u_n ASC;

这种填写的错误之处在于,MAX(date)是随机的,并不是和其他数据一一对应的,所以老老实实用子查询找到最大日期;即对应上一题的解法作为子查询
-- 考查知识点:表连接,对字符串排序;GROUP BY ;WHERE
SELECT u.name AS u_n, c.name AS c_n, l.date
  FROM login l LEFT JOIN user u ON l.user_id = u.id
               LEFT JOIN client c ON l.client_id = c.id
 WHERE (l.user_id, l.date) IN (SELECT user_id, MAX(date) 
                                 FROM login 
                                GROUP BY user_id)
  ORDER BY u_n ASC;

发表于 2021-02-22 17:05:03 回复(1)
select u.name u_n,c.name c_n,a.date
from(select l.user_id,l.client_id,max(date) date
from login l
group by user_id)as a
left join user u
    on u.id = a.user_id
left join client c
    on c.id = a.client_id
order by u.name;

请问这个有啥问题吗?   为啥会出现这种情况
发表于 2021-08-12 09:33:48 回复(1)
select t2.uname,t2.cname,t1.maxd
from
(select user_id,MAX(date) as maxd from login group by user_id) as t1
,
(select u.id as uid,u.name as uname,c.id as cid,c.name as cname,date
 from login l 
 inner join user u on l.user_id=u.id
 inner join client c on l.client_id=c.id) as t2
 where t1.user_id=t2.uid AND t1.maxd=t2.date
 order by t2.uname
本题的易错点在于
-group by 分组后默认显示的是第一条记录
-MAX() 取最大值
举个例子
select id,name,MAX(num)
from xx
group by id
显示出的 MAX值与name并不对应的,解决方法可以用子查询进行替代

t1表取出每个用户的最新登录日期
t2表将用户表,登陆表,型号表三表联立
最后将t1和t2进行user_id和日期的连接
完成题目
发表于 2021-04-02 14:45:39 回复(8)
select u.name as u_n, c.name as c_n, l.date as d from login as l 
inner join user as u on l.user_id = u.id 
inner join client as c on l.client_id = c.id 
group by l.user_id having max(l.date) 
order by u.name asc;
发表于 2020-09-09 22:37:27 回复(2)
方法1 :直接先从login选出user_id和其对应的最晚登陆时间,然后left join login,用user_id和date分别相等连接得到client相关的数据,然后分别通过ID left join user 和client 这两张表格得到user name和client name,最后,最外面,从刚刚的数据中直接取出我们需要的三列按user name排列就可以了
select u.name as u_n, c.name as c_n, l.date as date
from (
    select user_id, max(date) as date 
    from login
    group by user_id
) a left join login l on a.user_id = l.user_id and a.date = l.date
left join user u on l.user_id = u.id
left join client c on l.client_id = c.id
order by u.name
方法2:先不选择最近登陆日期,把login,user和client三个表哥先连好,然后再where(多个字段) in (子查询)选出最近登陆日期的行。
select u.name as u_n, c.name as c_n, l.date as date
from login l left join user u on l.user_id = u.id
left join client c on l.client_id = c.id
where (l.user_id,l.date) in (
    select user_id, max(date) from login group by user_id)
order by u.name
方法3: 使用窗口函数Max(date)  over(partition by user_id
select u.name as u_n, c.name as c_n, l.date as date
from (
    select *, max(date) over(partition by user_id) as max_date
    from login
)l left join user u on l.user_id = u.id 
left join client c on l.client_id = c.id
where date = max_date
order by u.name





发表于 2021-10-11 16:02:33 回复(2)
select u_n
,c_n
,date
from(
select u.name u_n
,c.name c_n
,l.date date
,row_number() over (partition by u.name order by l.date desc) ranking
# from login l
# left join user u
# on l.user_id = u.id
# left join client c
# on c.id = l.client_id  # 用这注释的5行替换下面3行,效果一样
from login l,user u,client c
where l.user_id = u.id
and c.id = l.client_id
) newtable
where ranking = 1
order by u_n;

发表于 2021-10-21 20:13:04 回复(0)
-- 关联子查询
SELECT U.name as u_n, C.name as c_n, L.date
FROM login L inner join user U
ON L.user_id = U.id 
inner join client C
on L.client_id = C.id  -- 将三个表连接
where L.date = (select max(date)
               from login L1 inner join user U1
               on L1.user_id = U1.id
               where U1.name = U.name
               group by U1.name)
order by u_n

发表于 2021-05-27 11:17:59 回复(0)
吐槽一下,答案还是有很多跑不起来的代码,以下代码能跑起来结果也对,但是不能通过本题,group by应该就u_n,c_n一块聚合,只聚合u_n只能通过测试,但不能运行
select u.name u_n,c.name c_n,max(date) d from login l,user u,client c 
where l.user_id=u.id and l.client_id=c.id
group by u_n,c_n
order by u.name asc

发表于 2020-09-16 15:30:50 回复(7)
请大佬帮忙看看这么写怎么不对,谢谢了
select u.name u_n,c.name c_n,t.date
from(
select user_id,max(date) date from login group by user_id 
)t 
join login l
on l.user_id = t.user_id
join user u 
on t.user_id = u.id 
join client c 
on l.client_id = c.id 
order by u.name


发表于 2022-07-29 11:32:45 回复(0)
select 
    u.name u_n,c.name c_n,l.date 
from 
    login l
left join user u on l.user_id=u.id
left join client c on l.client_id=c.id
where (user_id,date) in(select  user_id,max(date) from login group by user_id)
order by u_n asc;


今天终于把这个问题想清楚了,group by 默认取非聚合的第一条记录
发表于 2022-07-15 09:18:02 回复(1)
select u.name as u_n,c.name as c_n,l.date
from login l 
join user u on l.user_id = u.id
join client c on l.client_id = c.id
where(l.user_id,l.date) in (
    select user_id,max(date)
    from login 
    group by user_id
)
order by u.name;
发表于 2022-06-09 17:24:14 回复(0)
select u_n,c_n,`date` from
(select u.name u_n,c.name c_n,l.`date` `date`,
rank()over(partition by user_id order by `date` desc) d_rank  from
login l,`user` u,client c where l.user_id = u.id and l.client_id = c.id) as t
where t.d_rank = 1
order by u_n;
发表于 2022-05-24 19:18:14 回复(0)