【问题标题】:how to calculate user ranking from 2 different tables如何从 2 个不同的表中计算用户排名
【发布时间】:2017-11-06 14:31:50
【问题描述】:

我有一个users 表,其中包含phase1 和phase2 列,我需要计算每个阶段的用户排名并将其存储在这些字段中。

排名是根据不同的表格 points 计算的,其中我有每个用户的分阶段积分。

我想做的是

  1. 按阶段对每个用户的所有分数求和,并据此计算他的排名
  2. 如果用户积分相等,比较grade1的总和,如果也相等,比较grade2的总和
  3. 更新users 表,用他在每个阶段的排名

这是我的新表格与一些演示数据的样子 sql fiddle demo

目前我使用下面的代码从我的旧表中计算排名,其中排名和用户信息都在同一个表中

old sql fiddle demo

update users a
join (
  select id,
  (
      select count(distinct total) 
      from users d
      where c.total < d.total
  ) +1 rank
  from users c
) b on a.id = b.id
set a.rank = b.rank

【问题讨论】:

    标签: mysql


    【解决方案1】:

    oracle 中有一个名为 rank() 和 dense_rank() 的分析函数,它们对获取结果很有用。

    当您使用 mysql 时,我尝试将这些函数转换为 mysql 等效项。 您可以使用以下查询获得所需的结果,您可以使用它来更新用户表。如果在成绩上也有相同的逻辑,您可能需要进一步更改它。

    set @pk1 ='';
    set @rn1 =1;
    set @tot ='';
    set @val =1;
    
    
    SELECT  id,
            name,
            phase,
            phasetotal,
            denseRank
    FROM
    (
      SELECT  id,
              name,
              phase,
              phasetotal,
              @rn1 := if(@pk1=phase, @rn1+@val,1) as denseRank,
              @val := if(@pk1=phase, if(@tot=phasetotal, @val+1, 1),1) as value,
              @pk1 := phase,
              @tot := phasetotal     
      FROM
      (
            select users.id,users.name, points.phase, sum(points.points) 
            as phasetotal from users,points where users.id = points.userid 
            group by users.id, points.phase order by points.phase, phasetotal desc, points.grade1 desc, points.grade2 desc    
    ) A
    ) B;
    

    这里是更新查询

    set @pk1 ='';
    set @rn1 =1;
    set @tot ='';
    set @val =1;
    
    
    UPDATE users u join (
    SELECT  id,
            name,
            phase,
            phasetotal,
            denseRank
    FROM
    (
      SELECT  id,
              name,
              phase,
              phasetotal,
              @rn1 := if(@pk1=phase, @rn1+@val,1) as denseRank,
              @val := if(@pk1=phase, if(@tot=phasetotal, @val+1, 1),1) as value,
              @pk1 := phase,
              @tot := phasetotal     
      FROM
      (
            select users.id,users.name, points.phase, sum(points.points) 
            as phasetotal from users,points where users.id = points.userid 
            group by users.id, points.phase order by points.phase, phasetotal desc, points.grade1 desc, points.grade2 desc    
    ) A
    ) B ) C on u.id = C.id
       SET u.phase1 = CASE WHEN C.phase = 1 and u.phase1 = 0 THEN C.denseRank ELSE u.phase1 END,
           u.phase2 = CASE WHEN C.phase = 2 and u.phase2 = 0 THEN C.denseRank ELSE u.phase2 END;
    

    【讨论】:

    • 我有一个问题如何添加更新查询?并将points.phase 设置为denseRank
    • 我在下面添加了更新的查询。查看。如果您在 sqlfiddle 的左侧添加了它并且更新是 DML
    • 我不断获得所有用户的第一阶段排名 = 1,我想使用 foreach 吗?
    • 不知道你是如何保持 1 的,这是我所做的对我有用的方法:sqlfiddle
    • 好的,我在 1000 个用户上运行它,但它跳过了一些人的排名,例如,如果我按排名排序,以下缺少排名 49、76、92 ......这就是我注意到的每次有相似的点值时,下一个被跳过,假设在这种情况下 47-48 有相似的点,49 被跳过
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-14
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    相关资源
    最近更新 更多