繁体   English   中英

MySQL 5.6 - DENSE_RANK之类没有Order By的功能

[英]MySQL 5.6 - DENSE_RANK like functionality without Order By

我有这样一张桌子:

+------+-----------+
|caseID|groupVarian|
+------+-----------+
|1     |A,B,C,D,E  |
+------+-----------+
|2     |A,B,N,O,P  |
+------+-----------+
|3     |A,B,N,O,P  |
+------+-----------+
|4     |A,B,C,D,F  |
+------+-----------+
|5     |A,B,C,D,E  |
+------+-----------+

我想获得一个新的列nameVarian ,这样相同的groupVarian值具有由nameVarian表示的相同排名(例如:v1,v2等)。 但是,分配给特定groupVarian nameVarian值应该按groupVarian的顺序caseID (按照它们出现在表中的顺序)。

输出应该是这样的:

+------+-----------+----------+
|caseID|groupVarian|namevarian
+------+-----------+----------+
|1     |A,B,C,D,E  |v1        |
+------+-----------+----------+
|2     |A,B,N,O,P  |v2        |
+------+-----------+----------+
|3     |A,B,N,O,P  |v2        |
+------+-----------+----------+
|4     |A,B,C,D,F  |v3        |
+------+-----------+----------+
|5     |A,B,C,D,E  |v1        |
+------+-----------+----------+

对于MySQL版本<8.0OP的版本是5.6 ):

问题陈述看起来需要在groupVarian DENSE_RANK功能; 但事实并非如此。 正如@Gordon Linoff解释的那样

您似乎希望按照它们在数据中出现的顺序枚举它们。

假设您的表名是t (请相应地更改您的代码的表和字段名称)。 这是一种利用会话变量对于旧版本的MySQL )的方法,给出了期望的结果( DB Fiddle ):

SET @row_number = 0;
SELECT t3.caseID, 
       t3.groupVarian, 
       CONCAT('v', t2.num) AS nameVarian
FROM
  (
   SELECT 
     (@row_number:=@row_number + 1) AS num, 
     t1.groupVarian 
   FROM 
     (
      SELECT DISTINCT groupVarian 
      FROM t 
      ORDER BY caseID ASC 
     ) AS t1 
  ) AS t2 
INNER JOIN t AS t3 
  ON t3.groupVarian = t2.groupVarian 
ORDER BY t3.caseID ASC 

另外:我之前尝试模拟DENSE_RANK功能,效果很好。 虽然之前的查询也可以稍微调整一下,以实现DENSE_RANK功能。 但是,下面的查询效率更高,因为它创造了较小的派生表 ,并避免JOINgroupVarian

SET @row_number = 1;
SET @group_varian = '';

SELECT inner_nest.caseID, 
       inner_nest.groupVarian, 
       CONCAT('v', inner_nest.num) as nameVarian 
FROM (
        SELECT 
            caseID, 
            @row_number:=CASE
                           WHEN @group_varian = groupVarian THEN @row_number
                           ELSE @row_number + 1
                         END AS num, 
            @group_varian:=groupVarian as groupVarian 
        FROM
            t  
        ORDER BY groupVarian
     ) AS inner_nest 
ORDER BY inner_nest.caseID ASC 

你可以使用DENSE_RANK (MySQL 8.0):

SELECT *, CONCAT('v', DENSE_RANK() OVER(ORDER BY groupVarian)) AS namevarian
FROM tab
ORDER BY CaseID;

db <>小提琴演示

基本上,您想要枚举变体。 如果您只想要一个数字,那么您可以使用最小ID:

select t.*, min_codeId as groupVariantId
from t join
     (select groupVariant, min(codeId) as min_codeId
      from t
      group by groupVariant
     ) g
     on t.groupVariant = g.groupVariant;

但那不是你想要的。 您似乎希望按照它们在数据中出现的顺序枚举它们。 为此,您需要变量。 这有点棘手,但是:

select t.*, rn as groupVariantId
from t join
     (select g.*,
             (@rn := if(@gv = groupvariant, @gv,
                        if(@gv := groupvariant, @gv+1, @gv+1)
                       )
             ) as rn
      from (select groupVariant, min(codeId) as min_codeId
            from t
            group by groupVariant
            order by min(codeId)
           ) g cross join
           (select @gv := '', @rn := 0) params
     ) g
     on t.groupVariant = g.groupVariant;

使用变量很棘手。 一个重要的考虑因素:MySQL不保证SELECT中表达式的评估顺序。 这意味着变量不应该在一个表达式中分配,然后在另一个表达式中使用 - 因为它们可能以错误的顺序进行评估(另一个答案有这个错误)。

另外, order by需要在子查询中进行。 MySQL不保证在排序之前发生变量赋值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM