简体   繁体   English

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

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

I have a table like this: 我有这样一张桌子:

+------+-----------+
|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  |
+------+-----------+

I would like to get a new column nameVarian , such that same groupVarian values have same ranking represented by nameVarian (eg: v1, v2 and so on). 我想获得一个新的列nameVarian ,这样相同的groupVarian值具有由nameVarian表示的相同排名(例如:v1,v2等)。 However, nameVarian values assigned to a specific groupVarian should be as per the order of caseID (in the order they appear inside the table). 但是,分配给特定groupVarian nameVarian值应该按groupVarian的顺序caseID (按照它们出现在表中的顺序)。

The output should be something like: 输出应该是这样的:

+------+-----------+----------+
|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        |
+------+-----------+----------+

For MySQL version < 8.0 ( OP's version is 5.6 ): 对于MySQL版本<8.0OP的版本是5.6 ):

The problem statement looks like needing DENSE_RANK functionality over groupVarian ; 问题陈述看起来需要在groupVarian DENSE_RANK功能; however it is not. 但事实并非如此。 As explained by @Gordon Linoff : 正如@Gordon Linoff解释的那样

You appear to want them enumerated by the order they appear in the data. 您似乎希望按照它们在数据中出现的顺序枚举它们。

Assuming that your table name is t (please change the table and field name(s) accordingly for your code). 假设您的表名是t (请相应地更改您的代码的表和字段名称)。 Here is an approach utilizing session variables ( for older versions of MySQL ), giving the desired result ( DB Fiddle ): 这是一种利用会话变量对于旧版本的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 

Additionally: My earlier attempt to emulate DENSE_RANK functionality, works well. 另外:我之前尝试模拟DENSE_RANK功能,效果很好。 Although previous query can also be tweaked slightly to achieve DENSE_RANK functionality. 虽然之前的查询也可以稍微调整一下,以实现DENSE_RANK功能。 However, the following query is more efficient, as it creates lesser Derived tables , and avoids JOIN on groupVarian : 但是,下面的查询效率更高,因为它创造了较小的派生表 ,并避免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 

You could use DENSE_RANK (MySQL 8.0): 你可以使用DENSE_RANK (MySQL 8.0):

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

db<>fiddle demo db <>小提琴演示

Basically, you want to enumerate the variants. 基本上,您想要枚举变体。 If you just want a number, then you could use the minimum id: 如果您只想要一个数字,那么您可以使用最小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;

But that is not quite what you want. 但那不是你想要的。 You appear to want them enumerated by the order they appear in the data. 您似乎希望按照它们在数据中出现的顺序枚举它们。 For that, you need variables. 为此,您需要变量。 This is a bit tricky, but: 这有点棘手,但是:

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;

Using variables is tricky. 使用变量很棘手。 One important consideration: MySQL does not guarantee the order of evaluation of expressions in a SELECT . 一个重要的考虑因素:MySQL不保证SELECT中表达式的评估顺序。 That means that a variable should not be assigned in one expression and then used in another -- because they could be evaluated in the wrong order (another answer has this mistake). 这意味着变量不应该在一个表达式中分配,然后在另一个表达式中使用 - 因为它们可能以错误的顺序进行评估(另一个答案有这个错误)。

In addition, the order by needs to take place in a subquery. 另外, order by需要在子查询中进行。 MySQL does not guarantee that the variable assignment occurs before the sorting. MySQL不保证在排序之前发生变量赋值。

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

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