dbf
dbf

Reputation: 6499

Enumerate rows in mysql based on groups

I have a set of records, for example

A   B
1   5
1   6
1   9
2   1
2   8

where we have two groups (A=1 and A=2) and inside groups record are ordered by values in B.

And I need to add a column with enumeration inside each group

A   B   C
1   5   1
1   6   2
1   9   3
2   1   1
2   8   2

I tried to use nested query to fetch a number of records that have a value in B less than for current record given the same group id (A) but it is too slow. I use some enumeration of rows in other part of code (using select @rownum:=@rownum+1 num) but I enumerate all records there. So I am interested, is it possible to implement it iside query (if possible I'd like to avoid cursor loops etc). Thanks!

Upvotes: 2

Views: 2550

Answers (2)

Strawberry
Strawberry

Reputation: 33935

Prior to the introduction of common table expressions in MySQL 8, GL's first method would be fastest, but here's a couple of other ideas (also using older technology), just for fun...

1.

SELECT x.*
     , COUNT(*) rank 
  FROM my_table x 
  JOIN my_table y 
    ON y.a = x.a 
   AND y.b <= x.b 
 GROUP  
    BY x.a
     , x.b;

2.

SELECT x.* 
     , FIND_IN_SET(b,n) rank 
  FROM my_table x 
  JOIN 
     ( SELECT a 
            , GROUP_CONCAT(b ORDER BY b) n 
         FROM my_table 
        GROUP 
           BY a
     ) y 
    ON y.a = x.a;

Upvotes: 4

Gordon Linoff
Gordon Linoff

Reputation: 1269593

The most efficient way to do this is using variables:

select t.a, t.b,
       (@rn := if(@a = t.a, @rn + 1,
                  if(@a = t.a, 1, 1)
                 )
       ) as c
from table t cross join
     (select @a := '', @rn := 0) params
order by t.a, t.b;

An alternative approach uses a correlated subquery or join but assumes that the b values are unique for each a (or there is a unique column in the table):

select t.a, t.b,
       (select count(*) from table t2 where t2.a >= t.a) as c
from table t;

Upvotes: 3

Related Questions