每组前 3 名,包括 0

Posted

技术标签:

【中文标题】每组前 3 名,包括 0【英文标题】:Top 3 per group including 0 【发布时间】:2015-10-27 17:19:21 【问题描述】:

我有一个表,我希望从 Access 2010 开始,每周按 ErrorMargin 返回前 3 条记录。

我遇到的问题是 0 值被忽略了,我希望在平局的情况下只看到 1 条记录,而平局的记录总数超过 3。

我拥有的表格是:注意:帖子底部的 VBA 用于创建表格。

 TMID   WeekCommencing  ErrorMargin
    1   05-Oct-15   0
    1   12-Oct-15   2
    3   05-Oct-15   1
    3   12-Oct-15   1
    8   12-Oct-15   2
    9   05-Oct-15   0.333333333
    9   12-Oct-15   4
    12  05-Oct-15   0
    12  12-Oct-15   1.5

我现在的SQL是:

SELECT      T1.TMID,
            T1.WeekCommencing,
            T1.ErrorMargin,
            COUNT(*)
FROM        qry_REP_ErrorMargin T1 INNER JOIN qry_REP_ErrorMargin T2 ON
                T1.ErrorMargin <= T2.ErrorMargin AND
                T1.WeekCommencing = T2.WeekCommencing
GROUP BY    T1.TMID,
            T1.WeekCommencing,
            T1.ErrorMargin
HAVING      COUNT(*) <= 3
ORDER BY    T1.WeekCommencing,
            T1.ErrorMargin

这将返回下表,该表仅显示 2015 年 5 月 10 日的两条记录 - 还有两条 ErrorMargin 为 0 的记录,我希望它也返回其中一条。哪个没关系。 TMID 和 WeekCommencing 字段将构成该表的关键字段。

TMID    WeekCommencing  ErrorMargin Expr1003
9       05/10/2015      0.33        2
3       05/10/2015      1           1
1       12/10/2015      2           3
8       12/10/2015      2           3
9       12/10/2015      4           1

我尝试过其他解决方案,但还没有成功 - MS Access Select top n query grouped by multiple fields


创建表格的VBA代码:

Sub Create()

    Dim db As DAO.Database
    Set db = CurrentDb

    db.Execute "CREATE TABLE qry_REP_ErrorMargin" & _
        "(TMID LONG, WeekCommencing DATE, ErrorMargin Double)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (1,42282,0)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (1,42289,2)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (3,42282,1)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (3,42289,1)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (8,42289,2)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (9,42282,0.333333333333333)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (9,42289,4)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (12,42282,0)"
    db.Execute "INSERT INTO qry_REP_ErrorMargin" & _
        "(TMID, WeekCommencing, ErrorMargin) VALUES (12,42289,1.5)"

End Sub

【问题讨论】:

为什么 9 | 05/10/2015 | 0.33 | 2 有 count = 2 ?? 顺便说一句,您的查询使用您的数据返回不同的结果sqlfiddle.com/#!6/00f48/1 什么意思 top 3 for group 因为你说不关心 0 先走。你应该有双 0. 然后是 0.333 感谢您的 cmets Juan。我不明白您所说的计数为 2 的记录是什么意思,我认为 sqlfiddle 执行 SQL 的方式与 Access 的执行方式不同,因为它给出了不同的结果。你是对的 - 10 月 5 日应该有 0、0 和 0.333,但正如我在帖子中所说的 - 它忽略了 0,它不应该是。 【参考方案1】:

以下可能会做你想做的事:

SELECT em.*
FROM qry_REP_ErrorMargin as em
WHERE em.TMID IN (SELECT TOP 3 TMID
                  FROM qry_REP_ErrorMargin as em2
                  WHERE em2.WeekCommencing = em.WeekCommencing
                  ORDER BY em2.ErrorMargin
                 );

请注意,在平局的情况下,MS Access 可能会返回三行以上。如果您不想重复,则在 ORDER BY 中包含一个 id 列以防止出现平局:

ORDER BY em2.ErrorMargin, em2.TMID

【讨论】:

谢谢戈登。使用 ID 列上的额外 ORDER BY ,它返回的正是我想要的 - 带有示例数据。只需要使用各种数据集对其进行测试,我会在几个小时后回复以接受答案。

以上是关于每组前 3 名,包括 0的主要内容,如果未能解决你的问题,请参考以下文章

sql分组后取每组前三

每组前 N 个(MSSQL)[重复]

mysql分组后,取每组的前3条数据(并且有顺序)

无法在 sparksql 中选择每组前 10 条记录

mysql每组前N条

Laravel Eloquent/DB 选择每组前 1 行