MySQL 5.6 - DENSE_RANK like functionality without Order By

后端 未结 3 1831
北海茫月
北海茫月 2020-12-03 23:42

I have a table like this:

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


        
相关标签:
3条回答
  • 2020-12-04 00:24

    For MySQL version < 8.0 (OP's version is 5.6):

    The problem statement looks like needing DENSE_RANK functionality over groupVarian; however it is not. As explained by @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). Here is an approach utilizing session variables (for older versions of MySQL), giving the desired result (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. Although previous query can also be tweaked slightly to achieve DENSE_RANK functionality. However, the following query is more efficient, as it creates lesser Derived tables, and avoids JOIN on 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 
    
    0 讨论(0)
  • 2020-12-04 00:33

    You could use DENSE_RANK(MySQL 8.0):

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

    db<>fiddle demo

    0 讨论(0)
  • 2020-12-04 00:41

    Basically, you want to enumerate the variants. If you just want a number, then you could use the minimum 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. 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. MySQL does not guarantee that the variable assignment occurs before the sorting.

    0 讨论(0)
提交回复
热议问题