题解 | #获得积分最多的人(三)#
获得积分最多的人(三)
http://www.nowcoder.com/practice/d2b7e2a305a7499fb310dc82a43820e8
问题:请你写一个SQL查找积分最高的用户的id,名字,以及他的总积分是多少(可能有多个),查询结果按照id升序排序
方法一(笨办法):问题拆解:1.设定type=add条件,提取字段user_id和sum(grade_num) s1,对user_id分组,作为新表r1
2.设定type=reduce条件,提取字段user_id和sum(grade_num) s2,对user_id分组,作为新表r2
3.将r1和r2左链接,提取字段user_id和(s1-s2) s3(这里要注意下有些user_id是没有reduce的,得需要加一个ifnull来将空值替换成0),并按照s3降序排序,生成新表r3
4.将步骤3生成表r3和user链接,设定筛选条件排序为第一名(这里需要注意差值有可能有多个数字并列的情况,所以不能用orderby+limit的方法),提取需要的字段;
5.最后常规orderby
SELECT u.id,u.name, r3.s3 FROM
(SELECT r1.user_id, (s1-IFNULL(s2,0)) s3,
RANK() OVER(ORDER BY (s1-ifnull(s2,0)) DESC) r FROM
(SELECT user_id, SUM(grade_num) s1 FROM grade_info
WHERE type='add'
GROUP BY user_id) r1
LEFT JOIN
(SELECT user_id, SUM(grade_num) s2 FROM grade_info
WHERE type='reduce'
GROUP BY user_id) r2
ON r1.user_id=r2.user_id
) r3
JOIN user u
ON r3.user_id = u.id
WHERE r=1
ORDER BY u.id
方法二(精简方法)参考红名大神:SunburstRun的关键思路。
问题拆解:1.利用sum if嵌套使用的方法来进行筛选add和reduce,如果type是add,则sum(grade_num),否则输出-的sum(grade_num);
2.提取字段user_id,步骤1,然后对步骤1倒序排序,根据user_id分组
3.将步骤2新生成的表(重命名r1)和表user链接,设定筛选条件步骤2中的排序=1(这里的目的是第一名可能有并列数据的情况出现),然后提取需要的字段id、name、求和s
4.常规最后orderby即可。
SELECT u.id, u.name, grade_sum FROM
(SELECT user_id, SUM(IF(type='add',grade_num,-grade_num)) grade_sum,
RANK() OVER(ORDER BY grade_sum DESC) r
FROM grade_info
GROUP BY user_id) r1
JOIN user u
ON r1.user_id=u.id
WHERE r=1
ORDER BY u.id