所以我有一张表如下:
ID_STUDENT | ID_CLASS | GRADE
-----------------------------
1 | 1 | 90
1 | 2 | 80
2 | 1 | 99
3 | 1 | 80
4 | 1 | 70
5 | 2 | 78
6 | 2 | 90
6 | 3 | 50
7 | 3 | 90
Run Code Online (Sandbox Code Playgroud)
我需要对它们进行分组,排序和排序以给出:
ID_STUDENT | ID_CLASS | GRADE | RANK
------------------------------------
2 | 1 | 99 | 1
1 | 1 | 90 | 2
3 | 1 | 80 | 3
4 | 1 | 70 | 4
6 | 2 | 90 | 1
1 | 2 | 80 | 2
5 | 2 | 78 | 3
7 | 3 | 90 | 1
6 | 3 | 50 | 2
Run Code Online (Sandbox Code Playgroud)
现在我知道你可以使用临时变量进行排名,就像这里一样,但是如何对分组进行排序呢?感谢您的任何见解!
Qua*_*noi 32
SELECT id_student, id_class, grade,
@student:=CASE WHEN @class <> id_class THEN 0 ELSE @student+1 END AS rn,
@class:=id_class AS clset
FROM
(SELECT @student:= -1) s,
(SELECT @class:= -1) c,
(SELECT *
FROM mytable
ORDER BY id_class, id_student
) t
Run Code Online (Sandbox Code Playgroud)
这非常简单:
id_class第一个,id_student第二个排序.@student并@class初始化为-1@class用于测试是否输入下一组.如果id_class(存储在其中@class)的先前值不等于当前值(存储在其中id_class),@student则归零.否则是递增的.@class被赋值为新值id_class,它将在下一行的第3步测试中使用.Nic*_*art 12
Quassnoi的解决方案存在问题(标记为最佳答案).
我有同样的问题(即模拟SQL窗口功能在MySQL),我用来实现Quassnoi的解决方案,使用用户定义的变量来存储上一行值...
但是,也许在MySQL升级之后或者其他什么,我的查询不再起作用了.这是因为无法保证SELECT中字段的评估顺序.@class赋值可以在@student赋值之前进行求值,即使它是在SELECT之后放置的.
这在MySQL文档中提到如下:
作为一般规则,您不应该为用户变量赋值并在同一语句中读取值.您可能会得到您期望的结果,但这不能保证.涉及用户变量的表达式的评估顺序是未定义的,可能会根据给定语句中包含的元素进行更改; 此外,MySQL服务器版本之间的订单不保证相同.
来源:http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
最后我使用了这样的技巧,确保在读取后分配@class:
SELECT id_student, id_class, grade,
@student:=CASE WHEN @class <> id_class THEN concat(left(@class:=id_class, 0), 0) ELSE @student+1 END AS rn
FROM
(SELECT @student:= -1) s,
(SELECT @class:= -1) c,
(SELECT *
FROM mytable
ORDER BY id_class, grade desc
) t
Run Code Online (Sandbox Code Playgroud)
使用left()函数只是用来设置@class变量.然后,将left()(等于NULL)的结果连接到预期的结果是透明的.
不是很优雅,但它的工作原理!
SELECT g1.student_id
, g1.class_id
, g1.grade
, COUNT(*) AS rank
FROM grades AS g1
JOIN grades AS g2
ON (g2.grade, g2.student_id) >= (g1.grade, g1.student_id)
AND g1.class_id = g2.class_id
GROUP BY g1.student_id
, g1.class_id
, g1.grade
ORDER BY g1.class_id
, rank
;
Run Code Online (Sandbox Code Playgroud)
结果:
+------------+----------+-------+------+
| student_id | class_id | grade | rank |
+------------+----------+-------+------+
| 2 | 1 | 99 | 1 |
| 1 | 1 | 90 | 2 |
| 3 | 1 | 80 | 3 |
| 4 | 1 | 70 | 4 |
| 6 | 2 | 90 | 1 |
| 1 | 2 | 80 | 2 |
| 5 | 2 | 78 | 3 |
| 7 | 3 | 90 | 1 |
| 6 | 3 | 50 | 2 |
+------------+----------+-------+------+
Run Code Online (Sandbox Code Playgroud)
从上面修改,这可以工作,但它比我认为它需要更复杂:
SELECT ID_STUDENT, ID_CLASS, GRADE, RANK
FROM
(SELECT ID_STUDENT, ID_CLASS, GRADE,
@student:=CASE WHEN @class <> id_class THEN 1 ELSE @student+1 END AS RANK,
@class:=id_class AS CLASS
FROM
(SELECT @student:= 0) AS s,
(SELECT @class:= 0) AS c,
(SELECT *
FROM Students
ORDER BY ID_CLASS, GRADE DESC
) AS temp
) AS temp2
Run Code Online (Sandbox Code Playgroud)