通过使用窗口化函数ROW_NUMBER、RANK、DENSE_RANK和NTILE,可以让SQL对结果进行计数,从而确定每一行在结果集(或分区)中的具体位置。
理论部分
- ROW_NUMBER:所有行都具有唯一的编号。
- RANK:如果多个行具有相同的的顺序值,则允许这些行具有相同的值,但是对ROW_NUMBER值重新开始计数。例如,排名第一的是n个具有相同最高销售额的销售人员,而排名第二的是从n+1的RANK值开始的销售人员。
- DENSE_RANK:仍然是具有相同顺序值就有相同的值,但排名始终是递增的。例如排名第二的销售人员的排名始终是2,而不考虑有多少个排名并列第一的销售人员。
- NTILE:讲总的结果划分为x个类别,从1-x开始对这些类别排名。因此,NTILE(4)为第一组 1/4 的结果提供值1,而为第二组 1/4 的结果提供值2,以此类推。
测试脚本
-- 创建测试数据库RankTestDB
USE master
GO
IF EXISTS
(SELECT *
FROM sys.databases
WHERE name = 'RankTestDB')
BEGIN
DROP DATABASE RankTestDB;
PRINT 'Database RankTestDB has been dropped';
END
GO
CREATE DATABASE RankTestDB
GO
USE RankTestDB
GO
-- 创建测试表Foo
IF EXISTS
(SELECT *
FROM sys.objects
WHERE OBJECT_NAME(object_id) = 'Foo'
AND SCHEMA_NAME(schema_id) = 'dbo'
AND OBJECTPROPERTY(object_id, 'IsUserTable') = 1)
BEGIN
DROP TABLE dbo.Foo;
PRINT 'Table Foo has been dropped';
END
GO
CREATE TABLE Foo (
ID INT PRIMARY KEY IDENTITY,
Score INT DEFAULT(CAST(RAND()*101 AS INT))
)
GO
-- 向测试表Foo插入测试数据
DECLARE @i INT = 0;
WHILE (@i < 200)
BEGIN
INSERT INTO Foo DEFAULT VALUES;
SET @i = @i + 1;
END
-- 使用ROW_NUMBER、RANK、DENSE_RANK、NTILE查询
SELECT
ROW_NUMBER() OVER (ORDER BY Score DESC) AS RowNumber,
RANK() OVER (ORDER BY Score DESC) AS RankNumber,
DENSE_RANK() OVER (ORDER BY Score DESC) AS DenseRankNumber,
NTILE(4) OVER (ORDER BY Score DESC) AS Quartile,
Foo.*
FROM Foo
运行结果
开始10条数据
最后10条数据