MySQL透视表:如何提取各物业当前角色与用户的最新记录?
提取每个物业当前角色对应的用户记录
嘿,这个需求很典型,我来给你分享两种常用的解决思路,都是SQL层面的方案,适合大多数关系型数据库(比如MySQL 8+、PostgreSQL、SQL Server等)。
核心需求拆解
我们需要针对每个property_id(物业)的每个role(角色),只保留创建时间最晚的那条记录——也就是当前担任该角色的用户信息。你的示例里,物业1的Manager角色最新记录是用户67,Resident角色只有用户45,最终要得到这两行。
方法一:用ROW_NUMBER()窗口函数(最常用)
这个方法能精准筛选出每个组内的最新记录,如果有多个记录时间相同,只会保留其中一条(随机)。
WITH ranked_roles AS ( SELECT property_id, user_id, role, created_at, -- 按物业+角色分组,组内按创建时间倒序编号 ROW_NUMBER() OVER ( PARTITION BY property_id, role ORDER BY created_at DESC ) AS rn FROM your_table_name -- 把这里换成你的表名 ) -- 只取每个组里编号为1的(最新的)记录 SELECT property_id, user_id, role, created_at FROM ranked_roles WHERE rn = 1;
代码解释
PARTITION BY property_id, role:把数据按「物业+角色」拆分成独立的小组,比如物业1的Manager是一个组,物业1的Resident是另一个组。ORDER BY created_at DESC:每个小组内按创建时间从晚到早排序,最新的记录排在最前面。ROW_NUMBER()给每个小组内的行分配编号,最新的记录编号为1,后续的依次递增。- 最后筛选
rn = 1的行,就是我们要的「当前角色用户」记录。
用你的示例数据运行这个查询,会得到:
| property_id | user_id | role | created_at |
|---|---|---|---|
| 1 | 67 | Manager | 2020-05-19 00:00:00 |
| 1 | 45 | Resident | 2018-03-12 00:00:00 |
方法二:用RANK()窗口函数(处理同时间的多记录)
如果存在多个用户在同一时间担任同一个物业的同一角色(比如两个用户的created_at完全相同),用ROW_NUMBER()会随机丢弃其中一部分。这时可以换成RANK(),它会给所有时间相同的记录都分配编号1,保留所有最新的记录。
WITH ranked_roles AS ( SELECT property_id, user_id, role, created_at, -- 换成RANK(),同时间的记录会得到相同的编号 RANK() OVER ( PARTITION BY property_id, role ORDER BY created_at DESC ) AS rn FROM your_table_name ) SELECT property_id, user_id, role, created_at FROM ranked_roles WHERE rn = 1;
比如如果物业1有两个Manager的created_at都是2020-05-19,这个查询会把两个用户的记录都返回。
内容的提问来源于stack exchange,提问作者TheRealPapa




