MySQL5.6-无order-by的类似于排名的功能

fd3cxomn  于 2021-06-21  发布在  Mysql
关注(0)|答案(3)|浏览(319)

我有一张这样的table:

+------+-----------+
|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等)。然而, 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        |
+------+-----------+----------+
chhqkbe1

chhqkbe11#

对于mysql版本<8.0(op的版本是5.6):
问题陈述看起来需要密集的排名功能 groupVarian ; 但事实并非如此。正如@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 功能。但是,下面的查询效率更高,因为它创建的派生表较少,并且避免了连接 groupVarian :

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
ccgok5k5

ccgok5k52#

基本上,您需要枚举变体。如果您只需要一个号码,则可以使用最小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不保证变量赋值发生在排序之前。

qlckcl4x

qlckcl4x3#

你可以用 DENSE_RANK (mysql 8.0版):

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

db<>小提琴演示

相关问题