在基于多列的SQL查询中返回排名

时间:2018-01-31 20:02:28

标签: sql phpmyadmin

我有一个名为'allscores'的大型SQL表,类似于以下内容:

user    score    quiz_id   high_score
Bob     90       math      1
John    80       math      0
John    85       math      1
Steve   100      math      1
Bob     95       reading   0
Bob     100      reading   1
John    80       reading   1

'high_score'字段在表中开头,并且对于该测验的用户得分最高的行,总是设置为'1'。

我想要的是一个SQL查询,我可以在单个用户上运行以从两个测验(“数学”和“阅读”)中的每一个中获得最高分,以及他们在该测验的分数中的总体排名。到目前为止我所拥有的是:

SELECT `user`, `score`, `quiz_id` FROM `allscores` WHERE `user`="Bob" AND `high_score`="1"

将输出以下内容:

user    score    quiz_id
Bob     90       math
Bob     100      reading

此查询只是从每个测验中提取​​Bob的最高分 - 我想要添加的是该特定测验中分数的分数排名 - 所以输出如下:

user    score    quiz_id   rank
Bob     90       math      2
Bob     100      reading   1
由于史蒂夫得分较高,鲍勃的数学测验排名为'2',但由于得分最高,因此他的阅读排名为“1”。

如何将此排名列添加到现有查询?

1 个答案:

答案 0 :(得分:2)

这使用MS T-SQL语法,但如果您的SQL风格使用窗口函数,它应该是类似的。

SQL Fiddle

MS SQL Server 2017架构设置

CREATE TABLE t ( 
    [user] varchar(10)
  , score int
  , quiz_id varchar(10)
  , high_score bit
) ;

INSERT INTO t ([user], score, quiz_id, high_score)
VALUES
  ( 'Bob',90,'math',1 ) 
, ( 'John',80,'math',0 )
, ( 'Steve',100,'math',1 )
, ( 'Bob',95,'reading',0 )
, ( 'Bob',100,'reading',1 )
, ( 'John',85,'math',1 )
, ( 'John',80,'reading',1 )
;

MAIN QUERY

SELECT s1.[user]
  , s1.score
  , s1.quiz_id
  , s1.high_score
  --, s1.isUserHighScore
  , s1.ranking
FROM (

  SELECT 
      t.[user]
    , t.score
    , t.quiz_id
    , t.high_score
    --, ROW_NUMBER() OVER (PARTITION BY t.[user],t.quiz_id ORDER BY t.score DESC) AS isUserHighScore
    , DENSE_RANK() OVER (PARTITION BY t.quiz_id ORDER BY t.score DESC ) AS ranking
  FROM t

) s1

WHERE s1.[user]='Bob'
  --AND s1.isUserHighScore = 1
    AND s1.high_score = 1

<强> Results

| user | score | quiz_id | high_score | isUserHighScore | ranking |
|------|-------|---------|------------|-----------------|---------|
|  Bob |    90 |    math |       true |               1 |       2 |
|  Bob |   100 | reading |       true |               1 |       1 |

我使用ROW_NUMBER()来确定用户测验中的最高分数,然后使用DENSE_RANK()计算用户分数与其他分数的排名。 DENSE_RANK()RANK()之间的差异基本上是DENSE_RANK()不会在排名中留下任何空白。例如:2人得分为90,1得分为80,然后得到DENSE_RANK(),90s都是Rank 1,80则是Rank 2.使用RANK(),90s将是Rank 1和80将是Rank 3.