1、需求:查询用户详情的同时查询用户的排名
2、首先看下数据库表设计
分为会员用户表member_user
和会员等级表member_level
,升级的条件是根据经验值升级,表结构如下:
用户表 member_user
CREATE TABLE `member_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`mobile` varchar(11) DEFAULT NULL COMMENT '手机号',
`status` tinyint(4) NOT NULL COMMENT '状态',
`nickname` varchar(30) NOT NULL DEFAULT '' COMMENT '用户昵称',
`avatar` varchar(512) NOT NULL DEFAULT '' COMMENT '头像',
`sex` tinyint(4) DEFAULT '0' COMMENT '用户性别',
`level_id` bigint(20) DEFAULT NULL COMMENT '等级编号',
`experience` int(11) NOT NULL DEFAULT '0' COMMENT '经验',
`entry_time` datetime DEFAULT NULL COMMENT '入职时间',
`hobbies` varchar(200) DEFAULT NULL COMMENT '兴趣爱好',
`brief` varchar(300) DEFAULT NULL COMMENT '简介'
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=304 DEFAULT CHARSET=utf8mb4 COMMENT='会员用户';
会员等级表 member_level
CREATE TABLE `member_level` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '等级名称',
`level` int(11) NOT NULL DEFAULT '0' COMMENT '等级',
`experience` int(11) NOT NULL DEFAULT '0' COMMENT '升级经验',
`icon` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '等级图标',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态'
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会员等级';
3、根据用户id查询排名
基于等级 level_id
和经验 experience
进行排序,sql如下:
3.1、mysql 8.0以上可使用窗口函数
SELECT
mu.id,
mu.nickname,
mu.avatar,
ml.name AS level_name,
mu.experience,
RANK() OVER (ORDER BY ml.level DESC, mu.experience DESC) AS level_rank
FROM
member_user mu
JOIN
member_level ml ON mu.level_id = ml.id
WHERE
mu.id = #{id};
解释:
1、SELECT 子句:
选择我们需要的字段,包括会员 ID (member_id)、会员昵称 (member_nickname)、等级名称 (level_name)、经验 (experience),以及计算的排名 (level_rank)。
2、JOIN 语句:
通过 level_id 将 member_user 表与 member_level 表连接起来。这样可以获取会员对应的等级名称和等级详细信息。
3、RANK() OVER:
这是一个窗口函数,用来根据指定的排序规则对查询结果进行排名。在这里,我们首先按 level (等级) 降序排序,然后按 experience (经验) 降序排序。
以上sql没问题,可我使用的是 mysql 5.7
版本,不支持窗口函数,难道必须升级吗?升级过程出问题了咋整?好的,对症下药,多写两颗代码就搞定。
3.2、mysql 5.7 及更早版本不支持窗口函数。在这种情况下,我们可以使用子查询来实现类似的排名功能
SELECT
mu.id,
mu.nickname,
mu.avatar,
ml.name AS level_name,
mu.experience,
(
SELECT COUNT(*) + 1
FROM member_user mu2
JOIN member_level ml2 ON mu2.level_id = ml2.id
WHERE (ml2.level > ml.level) OR (ml2.level = ml.level AND mu2.experience > mu.experience)
) AS level_rank
FROM
member_user mu
JOIN
member_level ml ON mu.level_id = ml.id
WHERE
mu.id = #{id};
子查询的工作原理
1、子查询:
在主查询的每一行上,子查询都会计算出比当前会员等级高或等级相同但经验更高的会员数量。
2、排名:
将子查询的结果加 1 就是当前会员的排名。
总结
根据你的 MySQL 版本选择合适的解决方案。愿你大吉大利,没有bug。如果还有问题,欢迎讨论!