在MySQL中声明一个变量,需要在变量名之前使用@符号。FROM子句中的(@rank:= 0)部分可以进行变量初始化,而不需要单独的SET命令。更多关于MySQL自定义变量可以参考Mysql自定义变量的使用和MySQL官网文档用户自定义变量。
例子:
SELECT (@rank := @rank+1) AS rank FROM ( SELECT * FROM table_name ) a,(SELECT @rank :=0) b对本题中的销售金额进行排序后添加排名列的SQL语句:
SELECT a.mon AS r,a.sum AS x,@rank :=@rank + 1 AS j FROM (SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS mon, SUM(t.order_amount) AS sum FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time) ORDER BY SUM(t.order_amount) DESC) a,(SELECT @rank := 0) b执行结果如图:
这样就实现了简单的rank排名函数,也基本满足了题意。但是这样写还有一个问题需要注意,遇到销售金额相等的情况,名次也会加1。如果向表中再插入一条记录2018年5月的记录,使得5月份的销售金额和2月份相等:INSERT INTO orders(order_time,cate,goods_id,order_amount) VALUES ('2018-05-22 13:23:39', '果粒橙',111,877),再去执行刚才的查询操作,结果如图:
可以看见图中2018年2月和2018年5月的销售额都是877,2月排第2,5月排第3。这样排名貌似不合理吧?
还有更神奇的呢!再次执行相同的操作,结果却不相同。what?这次5月排第2,2月排第3了?什么情况?关于ORDER BY排序以后顺序为什么随机,我需要再好好研究一下MySQL底层原理。所以这个问题先留着。
如果是面试的话,在上面排名情况这个细节问题上就需要和面试官进行交流了,销售金额会不会有相等的情况?如果有相等的情况,遇到名次并列情况怎么办?如果说第1名有1个,第2名有两个并列,那么接下来的排名是第3名还是第4名呢?
接下来实现并列排名。如果题目要求相同数据并列排名,求排名的时候,需要拿前一个排名的数据来对比从而判断排名是否进行加1操作。SQL层面则需要自定义两个变量,一个记录之前排名的数据,一个记录现在的排名。如果之前排名的数据等于需要排名的数据,那么就是并列,排名不变。如果不相等,排名加1。也许我描述的不够清楚,看看SQL语句估计就明白了:
SELECT a.mon AS r,a.sum AS x, CASE WHEN @prevRank = a.sum THEN @curRank WHEN @prevRank := a.sum THEN @curRank := @curRank + 1 END AS j FROM (SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS mon, SUM(t.order_amount) AS sum FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time) ORDER BY SUM(t.order_amount) DESC) a,(SELECT @curRank :=0, @prevRank := NULL) b执行上述语句,2月和5月排名实现了并列,如图:
上面实现了普通并列排名,如果想实现高级并列排名(使上图中2018年4月数据排第4),需要定义3个变量,写起来有点复杂,这里先不写了。关于高级并列排名可以参考:在MySQL中实现Rank高级排名函数。
在第二步的基础上按照月份排序,完成。
经过了上面的步骤,离目标仅有一步之遥:按月份排序,还有替换别名。第二步的结果当成一张表,新建一个查询,对其进行月份排列,并把列名替换成为最终题目需要的列名即可。
SELECT tt.r AS '日期',tt.x AS '销售金额',tt.j AS '金额排名' FROM (SELECT a.mon AS r,a.sum AS x, CASE WHEN @prevRank = a.sum THEN @curRank WHEN @prevRank := a.sum THEN @curRank := @curRank + 1 END AS j FROM (SELECT DATE_FORMAT(t.order_time,'%Y-%m') AS mon, SUM(t.order_amount) AS sum FROM orders t WHERE YEAR(t.order_time) = 2018 GROUP BY MONTH(t.order_time) ORDER BY SUM(t.order_amount) DESC) a,(SELECT @curRank :=0, @prevRank := NULL) b) tt ORDER BY tt.r结果如我所愿:
请用SQL选出2018年2月每个类目销量最高的2个爆款商品以及排名先后。
类目 商品id 排名水果 223 1
花茶 444 1
花茶 5555 2
数码 45454 1