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函數裏的參數進行平分分區。

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