SQL中的排名问题

SQL中的排名问题

一、模拟学生成绩数据

1.1 创建学生表

首先,我们创建一个名为 "students" 的表来存储学生信息:

CREATE TABLE students (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  age INT
);

1.2 创建分数表

然后,我们创建一个名为 "scores" 的表来存储学生成绩:

CREATE TABLE scores (
  id INT PRIMARY KEY,
  student_id INT,
  subject VARCHAR(50),
  score INT,
  FOREIGN KEY (student_id) REFERENCES students(id)
);

1.3 维护学生表和分数表数据

接下来,我们向 "students" 表插入一些示例数据:

INSERT INTO students (id, name, age)
VALUES
  (1, '张三', 18),
  (2, '李四', 19),
  (3, '王五', 20),
  (4, '赵六', 19);

然后,我们向 "scores" 表插入一些示例数据:

INSERT INTO scores (id, student_id, subject, score)
VALUES
  (1, 1, '数学', 90),
  (2, 1, '语文', 85),
  (3, 1, '英语', 92),
  (4, 2, '数学', 90),
  (5, 2, '语文', 78),
  (6, 2, '英语', 85),
  (7, 3, '数学', 95),
  (8, 3, '语文', 92),
  (9, 3, '英语', 88),
  (10, 4, '数学', 82),
  (11, 4, '语文', 90),
  (12, 4, '英语', 85);

1.4 join查询

现在,我们已经创建了一个包含学生信息和成绩的学生成绩表。你可以根据自己的需要对表中的数据进行查询和操作。

例如,如果你想查询所有学生的成绩,可以使用以下 SQL 语句:

SELECT students.name, scores.subject, scores.score
FROM students
JOIN scores ON students.id = scores.student_id;

这将返回一个包含学生姓名、科目和成绩的结果集。

name subject score
张三 数学 90
张三 语文 85
张三 英语 92
李四 数学 90
李四 语文 78
李四 英语 85
王五 数学 95
王五 语文 92
王五 英语 88
赵六 数学 82
赵六 语文 90
赵六 英语 85

二、排名问题

排名中经常用到的ROW_NUMBER()RANK()DENSE_RANK()NTILE()这四个窗口函数。

以下使用模拟出的学生分数表数据分析其中一科的分数排名(分析数学成绩),数学分数结果:

SELECT students.name, scores.subject, scores.score
FROM students
JOIN scores ON students.id = scores.student_id
WHERE scores.subject = '数学';
name subject score
张三 数学 90
李四 数学 90
王五 数学 95
赵六 数学 82

2.1 ROW_NUMBER()

定义ROW_NUMBER()函数作用就是将SELECT查询到的数据进行排序,每一条数据加一个序号,他不能用做于学生成绩的排名,一般多用于分页查询,比如查询前10个 查询10-100个学生。

使用该函数进行排名,当分数一致的时候,排名不会出现重叠,排名次序是唯一的。

2.1.1 对学生成绩排序

WITH t AS (
	SELECT
		students.NAME,
		scores.SUBJECT,
		scores.score 
	FROM
		students
		JOIN scores ON students.id = scores.student_id 
	WHERE
		scores.SUBJECT = '数学'
) SELECT ROW_NUMBER() OVER (ORDER BY score DESC) AS 'rank',t.* FROM t;

降序排名后结果:

rank name subject score
1 王五 数学 95
2 张三 数学 90
3 李四 数学 90
4 赵六 数学 82

2.1.2 获取第2名的成绩信息

WITH t AS (
	SELECT
		students.NAME,
		scores.SUBJECT,
		scores.score 
	FROM
		students
		JOIN scores ON students.id = scores.student_id 
	WHERE
		scores.SUBJECT = '数学'
) 
SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY score DESC) AS 'rank',t.* FROM t) AS tb WHERE tb.rank = 2;

结果:

rank name subject score
2 张三 数学 90

2.2 RANK()

RANK()函数,顾名思义排名函数,可以对某一个字段进行排名,这里和ROW_NUMBER()有什么不一样呢?

ROW_NUMBER()是排序,当存在相同成绩的学生时,ROW_NUMBER()会依次进行排序,他们序号不相同,而Rank()则不一样。如果出现相同的,他们的排名是一样的。

示例

WITH t AS (
	SELECT
		students.NAME,
		scores.SUBJECT,
		scores.score 
	FROM
		students
		JOIN scores ON students.id = scores.student_id 
	WHERE
		scores.SUBJECT = '数学'
) SELECT RANK() OVER (ORDER BY score DESC) AS 'rank',t.* FROM t;

降序排序名结果:

rank name subject score
1 王五 数学 95
2 张三 数学 90
2 李四 数学 90
4 赵六 数学 82

2.1.1中的结果是ROW_NUMBER()函数的结果,上面的是RANK()函数的结果。

当出现两个学生成绩相同是里面出现变化。RANK()排名后是1-2-2-4,而ROW_NUMBER()则还是1-2-3-4

2.3 DENSE_RANK()

DENSE_RANK()函数也是排名函数,和RANK()功能相似,也是对字段进行排名,那它和RANK()到底有什么不同那?

特别是对于有成绩相同的情况,DENSE_RANK()排名是连续的,RANK()是跳跃的排名,一般情况下用的排名函数就是RANK()

示例

WITH t AS (
	SELECT
		students.NAME,
		scores.SUBJECT,
		scores.score 
	FROM
		students
		JOIN scores ON students.id = scores.student_id 
	WHERE
		scores.SUBJECT = '数学'
) SELECT DENSE_RANK() OVER (ORDER BY score DESC) AS 'rank',t.* FROM t;

降序排名后结果:

rank name subject score
1 王五 数学 95
2 张三 数学 90
2 李四 数学 90
3 赵六 数学 82

2.2中的结果是RANK()的结果,上面的结果是DENSE_RANK()的结果。

2.4 NTILE()

在 SQL 中,NTILE 函数用于将一个结果集分成指定数量的桶(buckets)或分组,并将每个行分配到对应的桶中。这可以用于数据分析、分组统计和排名等场景。

WITH t AS (
	SELECT
		students.NAME,
		scores.SUBJECT,
		scores.score 
	FROM
		students
		JOIN scores ON students.id = scores.student_id 
	WHERE
		scores.SUBJECT = '数学'
) SELECT ntile(2) OVER (ORDER BY score DESC) AS 'rank',t.* FROM t;

分区后的结果:

rank name subject score
1 王五 数学 95
1 张三 数学 90
2 李四 数学 90
2 赵六 数学 82

就是将查询出来的记录根据NTILE函数里的参数进行平分分区。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章