Select top N rows for each group

回眸只為那壹抹淺笑 提交于 2021-02-04 08:25:12

问题


I have the following MS Access DB schema:

I want to select rows from Items table ordered by Items.score so that there are at most Group.top_count rows for each group.

For example I have the following data in the tables:

Group table:

Items table:

I want to select top 2 items for group #1 and top 1 item for group #2. So the result must contain rows 1, 2 and 5.

There was a similar question at DBA stackexchange, but about SQL Server. So all answers used SQL Server syntax and I couldn't adapt it to work on MS Access.


回答1:


If there were a constant number per group, you could do:

select i.*
from items as i inner join
     groups as g
     on i.group_id = g.id
where i.id in (select top 2 i2.id
               from items i2
               where i2.group_id = i.group_id
               order by i2.score desc
              );

Instead, you will need to enumerate the values and this is expensive in MS Access:

select i.*
from (select i.*,
             (select count(*)
              from items i2
              where i2.group_id = i.group_id and
                    (i2.score < i.score or
                     i2.score = i.score and i2.id <= i2.id
                    )
             ) as seqnum
      from items as i
     ) as i inner join
     groups as g
     on i.group_id = g.id
where i.seqnum <= g.top_count;

This logic implements the equivalent of row_number(), which is the right way to solve this problem (if your database supports it).




回答2:


Using VBA to create the SQL command, perhaps try this (untested). It basically creates a UNION that joins each grouping, and allows you to run it on any size table (not sure if there's a limit to the UNION and if it starts to bog down after many, or perhaps there's a better method where you can open a recordset/table and just write the results into that recordset/table instead of doing the UNION thing.

SET DBS = CURRENTDB    
strSQL = ""
intMax = dmax("ID", "group")

FOR i = 1 TO intMax
    strSQL = strSQL & "SELECT TOP " & DLOOKUP("top_count","group","ID = " & I) & " ID " & _
        "FROM items WHERE group_id = " & i & " ORDER BY score "

    if i < intMax
        strSQL = strSQL & " UNION "
    endif
next i

dbs.execute strSQL


来源:https://stackoverflow.com/questions/39700550/select-top-n-rows-for-each-group

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