2014-12-19 49 views
0

我有一个表是这样的:次序等级更新

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.我将回答我自己的问题,但想知道是否有人有更好的解决方案,因为这有点不好意思;尽管我发现了很多推荐黑客的帖子。

+0

您的SQL语句在哪里? – Raptor 2014-12-19 02:35:03

+0

花了一段时间对我进行注释。 – 2014-12-19 02:44:53

回答

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 - 这将一些变量将被用来告诉何时incrament并重置排名

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

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

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

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

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 NT行列 - 设置职级相同,最后的排名时,其发病率是一样的前面,或者如果它不是递增等级”牛逼

names.incidence = @prevInc := names.incidence, 

8 - 这是设置一个变量包含先前发生黑客攻击,因此,我们可以告诉在未来itteration

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

9做的 - 这是一个黑客ŧ帽子设置一个变量来包含以前的地方,所以我们可以告诉下一步做什么

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; 
+0

这看起来比我的野蛮努力更清洁。不过,我并没有在开场明确说明我需要更新表格。我想我可以写一个新的,但更新会更受欢迎。 – 2014-12-19 02:42:33

+0

戈登 - 你可以用var示例填写更新查询吗???你声明“使用上面的子查询”,但第二个有一个交叉连接,并且Im uncelar在那里 - 我似乎可以找到其他引用... thx – jpmyob 2015-09-04 00:36:02