简体   繁体   中英

mysql limit in group by

Say i have this table fields:

Field1  Field2 Field3
a       1      1
a       1      2
a       1      3
a       1      4
a       2      1
a       2      2
a       2      3
a       3      1
b       1      1
b       1      2
b       1      3
b       2      1
c       1      1

and say i need to group by Field1 (because i need to some calucation on the data), is there a way to retrive only the first 2 elements grouped by Field2 (sorted desc)?

So for this example i'd like to retrive:

a,3,1
a,2,3
a,2,2
a,1,4
a,1,3
b,1,2
b,1,1
b,2,1
c,1,1

would be something like

SELECT field1, 
       Sum(field2), 
       Sum(field3) 
FROM   table t1 
WHERE  t1.Field1 IN (SELECT t2.Field1 
                     FROM   table t2 
                     WHERE  t2.Field1 = t1.Field1 
                     ORDER  BY Field2, 
                               Field3 DESC 
                     LIMIT  2) 
GROUP  BY field1 

A nice way to handle this if you are using MySQL 8+ or later is to use ROW_NUMBER :

WITH cte AS (
    SELECT Field1, Field2, Field3,
        ROW_NUMBER() OVER (PARTITION BY Field1, Field2 ORDER BY Field3 DESC) rn
    FROM yourTable
)

SELECT Field1, Field2, Field3
FROM cte
WHERE rn <= 2
ORDER BY Field1, Field2 DESC, Field3;

在此处输入图片说明

Demo

If you are not using MySQL 8+, then this problem gets fairly hairy, fairly quickly. The best way to do this in MySQL 5.7 or earlier would be to use session variables to simulate ROW_NUMBER . But, this requires some verbose code. You could also try to isolate the top two entries per group, but that two would take some verbose code. Really, if you have a long term need to run queries like this, then consider upgrading to MySQL 8+.

Pre MySQL 8.0 solution:

List only the last two values per (Field1, Field2) group:

select *
from test t
where t.Field3 >= coalesce((
  select t1.Field3
  from test t1
  where t1.Field1 = t.Field1
    and t1.Field2 = t.Field2
  order by t1.Field3 desc
  limit 1
  offset 1
), 0)
order by Field1, Field2, Field3;

Result:

Field1  Field2  Field3
a       1       3
a       1       4
a       2       2
a       2       3
a       3       1
b       1       2
b       1       3
b       2       1
c       1       1

Get SUMs per Field1 group:

select t.Field1
     , sum(Field2)
     , sum(Field3)
from test t
where t.Field3 >= coalesce((
  select t1.Field3
  from test t1
  where t1.Field1 = t.Field1
    and t1.Field2 = t.Field2
  order by t1.Field3 desc
  limit 1
  offset 1
), 0)
group by t.Field1

Result:

Field1  sum(Field2)     sum(Field3)
a       9               13
b       4               6
c       1               1

Fiddle demo

Note: this works fine, when the combination of (Filed1, Filed2, Filed3) is UNIQUE. If Field3 can be duplicated within a (Field1, Field2) group, we would need more complex logic to limit the result to two rows per group.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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