对每个项目进行投票后重新计算排名
Posted
技术标签:
【中文标题】对每个项目进行投票后重新计算排名【英文标题】:Recalculating ranks after each item is voted on 【发布时间】:2012-01-15 00:20:42 【问题描述】:我有一张允许用户投票的项目表。在这个表中,有一个 votes
列,保存该项目累积的票数,还有一个 rank
列,这是根据他们拥有的票数对所有项目进行排名(即大多数票获得排名 1,第二多获得排名 2,依此类推)
目前,我在每次投票后重新计算每个项目的排名。也就是说,当用户投票时,我在该项目的 votes
列中添加一个,然后使用以下查询更新每个排名:
SET @rank = 0
UPDATE items SET rank = @rank := @rank + 1 ORDER BY votes DESC
这在大多数情况下都有效,但不考虑投票关系。如果我有投票 [10, 4, 3, 0],我希望排名 [1, 2, 3, 4]
。但是,如果我有投票 [10, 10, 3, 0]
,我想要排名 [1, 1, 3, 4]
。这不会发生;我仍然获得排名[1, 2, 3, 4]
。
我怎样才能像上面描述的那样合并关系?
【问题讨论】:
【参考方案1】:我不会将排名保存在数据库中。您可以在显示结果的同时计算它。
$rank = 1;
$lastVotes = -1;
$lastAdd = 0;
$query = mysql_query("SELECT * FROM table WHERE * ORDER BY votes DESC", $link);
while( $row = mysql_fetch_array( $query ) )
// local variable with votes
$votes = $row['votes'];
// check if we have a tie
if( $lastVotes == $votes )
// don't change rank if there is a tie but inc $lastAdd
$lastAdd += 1;
else
// there is no tie: save last votes, adjust $rank and reset $lastAdd
$lastVotes = $votes;
$rank += $lastAdd;
$lastAdd = 1;
// $rank is your rank
【讨论】:
+1 表示“我不会将排名保存在数据库中”。当您将聚合值或计算值保存在另一列中时,它们不同步的机会比比皆是。但是,有一些案例,它们通常与性能有关。在这些情况下,触发器和/或单独的表可能是合适的。此类性能问题需要分析使用情况。【参考方案2】:这个不优雅的解决方案会返回你想要的:
update ITEMS I1
set rank =
(select count(*)
from ITEMS I2
where I2.VOTES >= I1.VOTES)
- (select count(*) - 1
from ITEMS I3
where I3.VOTES = I1.VOTES)
【讨论】:
这很好用,只是它似乎没有更新数据库中的排名数据;它只返回每一行的新排名。【参考方案3】:没有 mysql 实例可以尝试这个,但是像这样的东西怎么样:
SELECT v.id, v.votes, r.rank
FROM votes v
,(SELECT votes, @rownum = @rownum + 1 AS rank
FROM votes
GROUP BY votes
ORDER BY votes DESC
) r
WHERE v.votes = r.votes
ORDER BY rank
找出不同的“投票”集合,对它们进行排序,给每个人一个数字,然后用它来将数字(排名)与每个投票相关联。
【讨论】:
哦,我应该补充一点,排名是一个计算值,我也绝对不会将它存储在数据库中。【参考方案4】:确实取决于表大小和更新频率,但是触发器呢? MySQL- Trigger updating ranking
【讨论】:
以上是关于对每个项目进行投票后重新计算排名的主要内容,如果未能解决你的问题,请参考以下文章