MySQL中的sortingfunction

我不是MySQL的专家。 我需要找出客户的排名。 在这里,我为我的要求添加了相应的ANSI标准SQL查询。 请帮我把它转换成MySQL。

SELECT RANK() OVER (PARTITION BY Gender ORDER BY Age) AS [Partition by Gender], FirstName, Age, Gender FROM Person 

有没有什么function可以在MySQL中找出排名?

一种select是使用排名variables,如下所示:

 SELECT first_name, age, gender, @curRank := @curRank + 1 AS rank FROM person p, (SELECT @curRank := 0) r ORDER BY age; 

(SELECT @curRank := 0)部分允许variables初始化,而不需要单独的SET命令。

testing用例:

 CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1)); INSERT INTO person VALUES (1, 'Bob', 25, 'M'); INSERT INTO person VALUES (2, 'Jane', 20, 'F'); INSERT INTO person VALUES (3, 'Jack', 30, 'M'); INSERT INTO person VALUES (4, 'Bill', 32, 'M'); INSERT INTO person VALUES (5, 'Nick', 22, 'M'); INSERT INTO person VALUES (6, 'Kathy', 18, 'F'); INSERT INTO person VALUES (7, 'Steve', 36, 'M'); INSERT INTO person VALUES (8, 'Anne', 25, 'F'); 

结果:

 +------------+------+--------+------+ | first_name | age | gender | rank | +------------+------+--------+------+ | Kathy | 18 | F | 1 | | Jane | 20 | F | 2 | | Nick | 22 | M | 3 | | Bob | 25 | M | 4 | | Anne | 25 | F | 5 | | Jack | 30 | M | 6 | | Bill | 32 | M | 7 | | Steve | 36 | M | 8 | +------------+------+--------+------+ 8 rows in set (0.02 sec) 

这是一个通用的解决scheme,根据列对表进行sorting并赋予排名; 具有关系的行被赋予相同的等级(为此使用额外的variables):

 SET @prev_value = NULL; SET @rank_count = 0; SELECT id, rank_column, CASE WHEN @prev_value = rank_column THEN @rank_count WHEN @prev_value := rank_column THEN @rank_count := @rank_count + 1 END AS rank FROM rank_table ORDER BY rank_column 

请注意,第二个WHEN子句中有两个赋值语句。 示例数据:

 CREATE TABLE rank_table(id INT, rank_column INT); INSERT INTO rank_table (id, rank_column) VALUES (1, 10), (2, 20), (3, 30), (4, 30), (5, 30), (6, 40), (7, 50), (8, 50), (9, 50); 

输出:

 +------+-------------+------+ | id | rank_column | rank | +------+-------------+------+ | 1 | 10 | 1 | | 2 | 20 | 2 | | 3 | 30 | 3 | | 4 | 30 | 3 | | 5 | 30 | 3 | | 6 | 40 | 4 | | 7 | 50 | 5 | | 8 | 50 | 5 | | 9 | 50 | 5 | +------+-------------+------+ 

SQL小提琴

虽然最高的答案排名,它不分区,你可以做一个自我join得到整个事情分区:

 SELECT a.first_name, a.age, a.gender, count(b.age)+1 as rank FROM person a left join person b on a.age>b.age and a.gender=b.gender group by a.first_name, a.age, a.gender 

用例

 CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1)); INSERT INTO person VALUES (1, 'Bob', 25, 'M'); INSERT INTO person VALUES (2, 'Jane', 20, 'F'); INSERT INTO person VALUES (3, 'Jack', 30, 'M'); INSERT INTO person VALUES (4, 'Bill', 32, 'M'); INSERT INTO person VALUES (5, 'Nick', 22, 'M'); INSERT INTO person VALUES (6, 'Kathy', 18, 'F'); INSERT INTO person VALUES (7, 'Steve', 36, 'M'); INSERT INTO person VALUES (8, 'Anne', 25, 'F'); 

 Bill 32 M 4 Bob 25 M 2 Jack 30 M 3 Nick 22 M 1 Steve 36 M 5 Anne 25 F 3 Jane 20 F 2 Kathy 18 F 1 

丹尼尔版本的一个调整来计算百分位数和级别。 同样的两个人也会得到相同的等级。

 set @totalStudents = 0; select count(*) into @totalStudents from marksheets; SELECT id, score, @curRank := IF(@prevVal=score, @curRank, @studentNumber) AS rank, @percentile := IF(@prevVal=score, @percentile, (@totalStudents - @studentNumber + 1)/(@totalStudents)*100), @studentNumber := @studentNumber + 1 as studentNumber, @prevVal:=score FROM marksheets, ( SELECT @curRank :=0, @prevVal:=null, @studentNumber:=1, @percentile:=100 ) r ORDER BY score DESC 

查询样本数据的结果 –

 +----+-------+------+---------------+---------------+-----------------+ | id | score | rank | percentile | studentNumber | @prevVal:=score | +----+-------+------+---------------+---------------+-----------------+ | 10 | 98 | 1 | 100.000000000 | 2 | 98 | | 5 | 95 | 2 | 90.000000000 | 3 | 95 | | 6 | 91 | 3 | 80.000000000 | 4 | 91 | | 2 | 91 | 3 | 80.000000000 | 5 | 91 | | 8 | 90 | 5 | 60.000000000 | 6 | 90 | | 1 | 90 | 5 | 60.000000000 | 7 | 90 | | 9 | 84 | 7 | 40.000000000 | 8 | 84 | | 3 | 83 | 8 | 30.000000000 | 9 | 83 | | 4 | 72 | 9 | 20.000000000 | 10 | 72 | | 7 | 60 | 10 | 10.000000000 | 11 | 60 | +----+-------+------+---------------+---------------+-----------------+ 

丹尼尔和萨尔曼的答案相结合。 然而,排名不会像继续关系那样存在关系。 相反,它跳到下一个级别。 所以最大总是达到行数。

  SELECT first_name, age, gender, IF(age=@_last_age,@curRank:=@curRank,@curRank:=@_sequence) AS rank, @_sequence:=@_sequence+1,@_last_age:=age FROM person p, (SELECT @curRank := 1, @_sequence:=1, @_last_age:=0) r ORDER BY age; 

模式和testing用例:

 CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1)); INSERT INTO person VALUES (1, 'Bob', 25, 'M'); INSERT INTO person VALUES (2, 'Jane', 20, 'F'); INSERT INTO person VALUES (3, 'Jack', 30, 'M'); INSERT INTO person VALUES (4, 'Bill', 32, 'M'); INSERT INTO person VALUES (5, 'Nick', 22, 'M'); INSERT INTO person VALUES (6, 'Kathy', 18, 'F'); INSERT INTO person VALUES (7, 'Steve', 36, 'M'); INSERT INTO person VALUES (8, 'Anne', 25, 'F'); INSERT INTO person VALUES (9, 'Kamal', 25, 'M'); INSERT INTO person VALUES (10, 'Saman', 32, 'M'); 

输出:

 +------------+------+--------+------+--------------------------+-----------------+ | first_name | age | gender | rank | @_sequence:=@_sequence+1 | @_last_age:=age | +------------+------+--------+------+--------------------------+-----------------+ | Kathy | 18 | F | 1 | 2 | 18 | | Jane | 20 | F | 2 | 3 | 20 | | Nick | 22 | M | 3 | 4 | 22 | | Kamal | 25 | M | 4 | 5 | 25 | | Anne | 25 | F | 4 | 6 | 25 | | Bob | 25 | M | 4 | 7 | 25 | | Jack | 30 | M | 7 | 8 | 30 | | Bill | 32 | M | 8 | 9 | 32 | | Saman | 32 | M | 8 | 10 | 32 | | Steve | 36 | M | 10 | 11 | 36 | +------------+------+--------+------+--------------------------+-----------------+ 

@Sam,你的观点是优秀的概念,但我想你误解了MySQL文档在被引用的页面上说的是什么 – 或者我误解了:-) – 我只是想添加这个,所以如果有人感到不舒服@丹尼尔的回答他们会更放心,或者至less深入一点。

您看到SELECT内部的“@curRank:= @curRank + 1 AS排名”不是“一个语句”,它是语句的一个“primefaces”部分,因此它应该是安全的。

您引用的文档继续显示在语句的2(primefaces)部分中的相同用户定义variables(例如,“SELECT @curRank,@curRank:= @curRank + 1 AS rank”)的示例。

有人可能会认为@curRank在@Daniel的答案中使用了两次:(1)“@curRank:= @curRank + 1 AS排名”和(2)“(SELECT @curRank:= 0)r”用法是FROM子句的一部分,我敢肯定它是保证被首先评估; 基本上使它成为第二个和之前的陈述。

事实上,在你引用的那个MySQL文档页面上,你会在注释中看到相同的解决scheme – 它可能是@Daniel从中得到的; 是的,我知道这是评论,但它是官方文档页面上的评论,并确实有一定的权重。

如果你想排名只有一个人,你可以做到以下几点:

 SELECT COUNT(Age) + 1 FROM PERSON WHERE(Age < age_to_rank) 

这个排名对应于oracle的RANK函数(如果你有同龄人,他们得到相同的排名,而排名在后面是不连续的)。

这比在子查询中使用上述解决scheme中的一种更快一些,并且从中进行select以获得一个人的排名。

这可以用来排名每个人,但比上述解决scheme慢。

 SELECT Age AS age_var, ( SELECT COUNT(Age) + 1 FROM Person WHERE (Age < age_var) ) AS rank FROM Person