在mysql中的组内排序

时间:2011-12-06 01:37:10

标签: mysql sql sorting rank percentile

我有一个面板数据集:即timesidsvalues。我想根据每个日期的值进行排名。我可以通过运行来简单地实现这种排序:

select * from tbl order by date, value

我遇到的问题是,一旦表以这种方式排序,我如何检索每个组的行号(也就是说,对于每个日期,我希望有一个名为rank的列,从1到N )。

示例:

输入:

Date, ID, Value
 d1, id1, 2
 d1, id2, 1
 d2, id1, 10
 d2, id2, 11

输出:

Date, ID, Value, Rank
 d1, id2, 1, 1
 d1, id1, 2, 2
 d2, id1, 10, 1
 d2, id2, 11, 2

3 个答案:

答案 0 :(得分:3)

缺少窗口函数,您可以订购tbl并使用用户变量自行计算分区的排名(“日期”值):

SELECT "date",                                                -- D) Desired columns
       id,
       value,
       rank
  FROM (SELECT "date",                                        -- C) Rank by date
               id,
               value,
               CASE COALESCE(@partition, "date")
                 WHEN "date" THEN @rank := @rank + 1
                 ELSE             @rank := 1
               END AS rank,
               @partition := "date" AS dummy
          FROM (SELECT @rank := 0 AS rank,                    -- A) User var init
                       @partition := NULL AS partition) dummy
               STRAIGHT_JOIN
               (  SELECT "date",                              -- B) Ordering query
                         id,
                         value
                    FROM tbl
                ORDER BY date, value) tbl_ordered;

更新

那么,那个查询在做什么?

我们正在使用用户变量来“循环”整个排序结果集,递增或重置计数器(@rank),具体取决于结果集的哪个连续段(在{中跟踪) {1}})我们在。

在查询 A 中,我们初始化两个用户变量。在查询 B 中,我们按照我们需要的顺序获取您的表的记录:首先按日期,然后按值。 A B 一起制作派生表@partition,如下所示:

tbl_ordered

请注意,我们并不关心列rank | partition | "date" | id | value ---- + --------- + ------ + ---- + ----- 0 | NULL | d1 | id2 | 1 0 | NULL | d1 | id1 | 2 0 | NULL | d2 | id1 | 10 0 | NULL | d2 | id2 | 11 dummy.rank - 它们只是我们如何初始化变量dummy.partition@rank的事故。< / p>

在查询 C 中,我们遍历派生表的记录。我们正在做的事情或多或少是以下伪代码的作用:

@partition

最后,查询 D 会为 C 中的所有列投影除之外的所有列,其中包含rank = 0 partition = nil foreach row in fetch_rows(sorted_query): (date, id, value) = row if partition is nil or partition == date: rank += 1 else: rank = 1 partition = date stdout.write(date, id, value, rank, partition) (我们将其命名为{{1}并且不需要显示)。

答案 1 :(得分:1)

我知道这是一个老问题,但这是一个较短的答案:

SELECT w.*, if(
      @preDate = w.date,
      @rank := @rank + 1,
      @rank := (@preDate :=w.date) = w.date
    ) rank
FROM tbl w
JOIN (SELECT @preDate := '' )a
ORDER BY date, value

答案 2 :(得分:0)

这可以解决这个问题吗?

select [DATE],ID,Value, 
(DENSE_RANK()  OVER (   
   PARTITION BY ID
 ORDER BY Date) )AS [DenseRank],    
ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY [Date] DESC) AS RN     
from SomeTable