为每个组选择前 N 行
Posted
技术标签:
【中文标题】为每个组选择前 N 行【英文标题】:Select top N rows for each group 【发布时间】:2016-09-26 10:33:45 【问题描述】:我有以下 MS Access 数据库架构:
我想从 Items 表中选择按 Items.score 排序的行,以便每个组最多有 Group.top_count 行。
例如我在表格中有以下数据:
组表:
物品表:
我想为第 1 组选择前 2 项,为第 2 组选择前 1 项。所以结果必须包含第 1、2 和 5 行。
有一个similar question at DBA stackexchange,但是关于 SQL Server。所以所有答案都使用 SQL Server 语法,我无法将其调整为在 MS Access 上工作。
【问题讨论】:
【参考方案1】:如果每组有一个常数,你可以这样做:
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
);
相反,您需要枚举值,这在 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;
这个逻辑实现了row_number()
的等价物,这是解决这个问题的正确方法(如果你的数据库支持的话)。
【讨论】:
【参考方案2】:使用 VBA 创建 SQL 命令,不妨试试这个(未经测试)。它基本上创建了一个连接每个分组的 UNION,并允许您在任何大小的表上运行它(不确定 UNION 是否有限制,以及它是否在很多之后开始陷入困境,或者也许有更好的方法可以打开一个记录集/表,只需将结果写入该记录集/表,而不是执行 UNION 操作。
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
【讨论】:
以上是关于为每个组选择前 N 行的主要内容,如果未能解决你的问题,请参考以下文章