MySQL更新中的序数排名

时间:2014-12-19 02:32:02

标签: mysql ranking

我有这样一张桌子:

id    name    incidence    placeRef
1     John    10           1
2     Ann     9            1
3     Paul    9            1
4     Carl    8            1
5     John    4            1
6     Ann     4            1
7     Paul    7            1
8     Carl    1            1

我想使用ordinal ranking method对这些进行排名。哪个会在我的表中添加等级:

id    name    incidence    placeRef    rank
1     John    10           1           1
2     Ann     9            1           2
3     Paul    9            1           2
4     Carl    8            1           4
5     John    4            1           2
6     Ann     4            1           2
7     Paul    7            1           1
8     Carl    1            1           4

如何实现这一目标?

N.B。我将回答我自己的问题,但想知道是否有人有任何更好的解决方案,因为它有点hacky;虽然我发现很多帖子都在为这种情况推荐黑客。

2 个答案:

答案 0 :(得分:2)

您可以使用变量或相关子查询执行此操作。子查询方法如下所示:

select t.*,
       (select 1 + count(t2.incidence)
        from table t2
        where t2.incidence > t.incidence
       ) as rank
from table t;

变量方法有点棘手,因为你必须记住具有给定值的匹配行的数量:

  select t.*,
         (@rn := if(@i = t.incidence, if(@cnt := @cnt + 1, @rn, @rn),
                    @cnt + if(@i := t.incidence, if(@cnt := 1, @rn, @rn), @rn)
                   )
         ) as rank
  from table t cross join
       (select @i := 0, @rn := 0, @cnt := 1) vars
  order by incidence desc;

编辑:

如果您想更新表格,只需将updatejoin一起使用:

update table t join
       (<either subquery above>) s
      on t.id = s.id
    set t.rank = s.rank;

答案 1 :(得分:1)

以下作品:

UPDATE names
JOIN ( SELECT * FROM names ORDER BY placeRef, incidence DESC ) AS p ON p.id = names.id,
( SELECT @curRank := 0, @nextRank := 0, @prevInc := 9999999999, @prevPlace := 0 ) AS v
SET 
names.rank = IF(  @prevPlace != p.placeRef, @curRank := 0, 0 ),
names.rank = IF(  @prevPlace != p.placeRef, @nextRank := 0, 0 ),
names.rank = IF(  @prevInc = p.incidence, @nextRank := @nextRank + 1, @curRank := @nextRank := @nextRank + 1 ),
names.rank = IF(  @prevInc = p.incidence, @curRank := @curRank, @curRank := @nextRank ),
names.incidence = @prevInc := names.incidence,
names.placeRef = @prevPlace := names.placeRef;

说明:

UPDATE names

1 - 设置要更新的表

JOIN ( SELECT * FROM names ORDER BY placeRef, incidence DESC ) AS p ON p.id = names.id,

2 - 这使得虚拟表的结果有序,因此可以应用排名

( SELECT @curRank := 0, @nextRank := 0, @prevInc := 9999999999, @prevPlace := 0 ) AS v

3 - 这设置了一些变量,用于判断何时进行篡改和重置等级

names.rank = IF(  @prevPlace != p.placeRef, @curRank := 0, 0 ),

4 - 当MySQL迭代到新的地方时,这是一个将当前等级重置为0的黑客

names.rank = IF(  @prevPlace != p.placeRef, @nextRank := 0, 0 ),

5 - 当MySQL迭代到一个新的地方时,这是一个将下一个等级重置为0的黑客

names.rank = IF(  @prevInc = p.incidence, @nextRank := @nextRank + 1, @curRank := @nextRank := @nextRank + 1 ),

6 - 当当前发病率与之前的发病率相同时,这是一个更新下一个和当前等级的黑客

names.rank = IF(  @prevInc = p.incidence, @curRank := @curRank, @curRank := @nextRank ),

7 - 当它的发生率与前一个相同时,它将等级设置为与最后一个等级相同,或者如果它不是

则增加等级
names.incidence = @prevInc := names.incidence,

8 - 这是一个设置变量以包含先前发生率的hack,因此我们可以告诉下一次尝试该做什么

names.placeRef = @prevPlace := names.placeRef;

9 - 这是一个设置变量以包含前一个地方的黑客,所以我们可以告诉下一次尝试该做什么