Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于MySQL中的多个列确定排名_Mysql_Sql_Sql Rank - Fatal编程技术网

基于MySQL中的多个列确定排名

基于MySQL中的多个列确定排名,mysql,sql,sql-rank,Mysql,Sql,Sql Rank,我有一个有3个字段的表,我想根据用户id和游戏id对列进行排名 下面是SQL Fiddle: 我已经有了这张表: user_id | game_id | game_detial_sum | --------|---------|--------------------| 6 | 10 | 1000 | 6 | 11 | 260 | 7 | 10 |

我有一个有3个字段的表,我想根据用户id和游戏id对列进行排名

下面是SQL Fiddle:

我已经有了这张表:

 user_id | game_id |   game_detial_sum  |
 --------|---------|--------------------|
 6       | 10      |  1000              |   
 6       | 11      |  260               |
 7       | 10      |  1200              |
 7       | 11      |  500               |
 7       | 12      |  360               |
 7       | 13      |  50                | 
预期产出:

user_id  | game_id |   game_detial_sum  |  user_game_rank  |
 --------|---------|--------------------|------------------|
 6       | 10      |  1000              |   1              |
 6       | 11      |  260               |   2              |
 7       | 10      |  1200              |   1              |
 7       | 11      |  500               |   2              |
 7       | 12      |  360               |   3              |
 7       | 13      |  50                |   4              |
我迄今为止的努力:

SET @s := 0; 
SELECT user_id,game_id,game_detail, 
       CASE WHEN user_id = user_id THEN (@s:=@s+1) 
            ELSE @s = 0 
       END As user_game_rank 
FROM game_logs
编辑:(来自OP):排序基于
游戏详细信息的降序

游戏顺序(详情)

在(
FROM
子句内的子查询)中,我们对数据进行排序,使所有具有相同
user\u id
值的行聚集在一起,并根据
game\u detail
按降序对它们进行进一步排序

现在,我们使用这个结果集并使用条件
CASE..WHEN
表达式来计算行编号。这将类似于循环技术(我们在应用程序代码中使用,例如:PHP)。我们将把前一行的值存储在用户定义的变量中,然后对照前一行检查当前行的值。最后,我们将相应地分配行号

编辑:基于MySQL和@Gordon Linoff的观察:

涉及用户变量的表达式的求值顺序为 未定义。例如,不能保证选择@a,@a:=@a+1 首先计算@a,然后执行赋值

我们需要计算行号,并将
用户id
值分配给同一表达式中的
@u
变量

SET @r := 0, @u := 0; 
SELECT
  @r := CASE WHEN @u = dt.user_id 
                  THEN @r + 1
             WHEN @u := dt.user_id /* Notice := instead of = */
                  THEN 1 
        END AS user_game_rank, 
  dt.user_id, 
  dt.game_detail, 
  dt.game_id 

FROM 
( SELECT user_id, game_id, game_detail
  FROM game_logs 
  ORDER BY user_id, game_detail DESC 
) AS dt 
结果

| user_game_rank | user_id | game_detail | game_id |
| -------------- | ------- | ----------- | ------- |
| 1              | 6       | 260         | 11      |
| 2              | 6       | 100         | 10      |
| 1              | 7       | 1200        | 10      |
| 2              | 7       | 500         | 11      |
| 3              | 7       | 260         | 12      |
| 4              | 7       | 50          | 13      |
| user_id | game_id | game_detail | user_game_rank |
| ------- | ------- | ----------- | -------------- |
| 6       | 11      | 260         | 1              |
| 6       | 10      | 100         | 2              |
| 7       | 10      | 1200        | 1              |
| 7       | 11      | 500         | 2              |
| 7       | 12      | 260         | 3              |
| 7       | 13      | 50          | 4              |


MySQL的一条有趣的注释,我最近发现:

MySQL的早期版本可以为 语句中的用户变量,而不是SET。此功能是 MySQL 8.0支持向后兼容,但受 在MySQL的未来版本中删除

另外,感谢SO的一位同事,MySQL团队发现了这个博客:

一般的观察结果是,在同一查询块中使用
ORDER BY对用户变量进行求值,并不能确保值总是正确的。随着时间的推移,MySQL优化器可能会就位并更改我们假定的评估顺序

解决此问题的最佳方法是升级到MySQL 8+并利用以下功能:

模式(MySQL v8.0)

结果

| user_game_rank | user_id | game_detail | game_id |
| -------------- | ------- | ----------- | ------- |
| 1              | 6       | 260         | 11      |
| 2              | 6       | 100         | 10      |
| 1              | 7       | 1200        | 10      |
| 2              | 7       | 500         | 11      |
| 3              | 7       | 260         | 12      |
| 4              | 7       | 50          | 13      |
| user_id | game_id | game_detail | user_game_rank |
| ------- | ------- | ----------- | -------------- |
| 6       | 11      | 260         | 1              |
| 6       | 10      | 100         | 2              |
| 7       | 10      | 1200        | 1              |
| 7       | 11      | 500         | 2              |
| 7       | 12      | 260         | 3              |
| 7       | 13      | 50          | 4              |

MySQL 8.0版之前的最佳解决方案如下:

select gl.*, 
       (@rn := if(@lastUserId = user_id, @rn + 1,
                  if(@lastUserId := user_id, 1, 1)
                 )
        ) as user_game_rank
from (select gl.*
      from game_logs gl
      order by gl.user_id, gl.game_detail desc
     ) gl cross join
     (select @rn := 0, @lastUserId := 0) params;

排序是在子查询中完成的。从MySQL 5.7开始,这是必需的。变量赋值都在一个表达式中,因此表达式的不同求值顺序无关紧要(MySQL也不保证表达式的求值顺序)。

您可以使用一个非常简单的相关子查询:

SELECT *, (
    SELECT COUNT(DISTINCT game_detail) + 1
    FROM game_logs AS x
    WHERE user_id = t.user_id AND game_detail > t.game_detail
) AS user_game_rank
FROM game_logs AS t
ORDER BY user_id, user_game_rank


它比用户变量更慢但更可靠。只需一个连接就可以打破它们。

是基于
game\u id
的升序或
game\u detail
的降序的游戏顺序_detail@GordonLinoffMySQL团队的特定博客可能会有所帮助:2)这个答案是错误的,因为它没有根据
游戏详细信息
按降序排列。这似乎是可行的,因为(不幸的是)OP的样本数据本身是不够的(已经排序)。第三,afaik,这个答案和另一个答案(我的答案)中的用户变量的计算是在两个不同的表达式中进行的(用逗号分隔)。如果具体的差异可以得到解决,我会很高兴的showcased@MadhurBhaiya:我添加了一个
orderby
@juergend,我也会要求你读一次这个博客:基本上MySQL不保证评估是在
orderby
之前还是之后进行(由于自身的优化)@juergend我在评论另一个问题时,与Nick聊过这类问题,以及某些场景中的意外行为等。你可能对同样的东西感兴趣:@MadhurBhaiya。你说得对。这与您的错误相同。
@lastUserId:=user\u id
仍然可以在
if()
表达式之前求值。肯定是
if(user_id:=@lastUserId
中涉及了一些技巧,但无法理解。这是怎么回事?一些解释会很方便。@MadhurBhaiya…那一行是个错误,已被删除。它没有在计算中使用。现在有意义了。+1