MySQL 5.6 - DENSE_RANK like functionality without Order By

眉间皱痕 提交于 2019-11-28 02:09:29

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 

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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!