从每组 sqlite 中选择前 n 条记录

Posted

技术标签:

【中文标题】从每组 sqlite 中选择前 n 条记录【英文标题】:select top n record from each group sqlite 【发布时间】:2015-03-23 00:56:45 【问题描述】:

我正在尝试从如下所示的数据库表结果中选择前 2 条记录

SubjectId |  StudentId | Levelid | total
------------------------------------------
 1        |  1         |   1     | 89
 1        |  2         |   1     | 77
 1        |  3         |   1     | 61
 2        |  4         |   1     | 60
 2        |  5         |   1     | 55
 2        |  6         |   1     | 45

我试过这个查询

SELECT rv.subjectid,
       rv.total,
       rv.Studentid,
       rv.levelid
  FROM ResultView rv
       LEFT JOIN ResultView rv2
              ON ( rv.subjectid = rv2.subjectid 
    AND
rv.total <= rv2.total ) 
 GROUP BY rv.subjectid,
          rv.total,
          rv.Studentid
HAVING COUNT( * ) <= 2
order by rv.subjectid desc  

但有些主题,例如缺少的地方,我什至尝试了以下链接的建议

How to select the first N rows of each group?

但我得到的每个 subjectid 多于两个

我做错了什么?

【问题讨论】:

HAVING COUNT( * ) &lt;= 3 过滤掉任何包含 3 行或更多行的组。但是您并不是要排除整个组,而是要排除第二组之后的任何行。 HAVING COUNT( * ) &lt;= 3 是错字,已更正 如果您提供所需输出的示例,则更容易提供答案。 【参考方案1】:

希望我能正确理解您的问题。让我知道这是否正确:

我重新创建了你的表:

CREATE TABLE stack (
       SubjectId INTEGER(10),
       StudentId INTEGER(10),
       Levelid INTEGER(10),
       total INTEGER(10)
       )
;

插入的值

INSERT INTO stack VALUES
       (1,1,1,89),
       (1,2,1,77),
       (1,3,1,61),
       (2,4,1,60),
       (2,5,1,55),
       (2,6,1,45)
;

如果您尝试按 Levelid 获取***组(按总字段排序,假设 StudentID 作为主键):

SELECT * 
FROM stack AS a
WHERE a.StudentID IN (
      SELECT b.StudentID
      FROM stack AS b
      WHERE a.levelid = b.levelid
      ORDER BY b.total DESC
      LIMIT 2
      )
;

产生这个结果:

SubjectId | StudentId | Levelid | total
1         | 1         | 1       | 89
1         | 2         | 1       | 77

SubjectId 前 2 名的示例,按总数排序:

SELECT * 
FROM stack AS a
WHERE a.StudentID IN (
      SELECT b.StudentID
      FROM stack AS b
      WHERE a.subjectID = b.subjectID
      ORDER BY b.total DESC
      LIMIT 2
      )
;

结果:

SubjectId | StudentId | Levelid | total
1         | 1         | 1       | 89
1         | 2         | 1       | 77
2         | 4         | 1       | 60
2         | 5         | 1       | 55

我希望这就是您正在寻找的答案。

【讨论】:

好消息是它有效,坏消息是每 10K 记录执行需要 30 秒。【参考方案2】:

您可以使用相关子查询:

select  *
from    ResultView rv1
where   SubjectId || '-' || StudentId || '-' || LevelId in
        (
        select  SubjectId || '-' || StudentId || '-' || LevelId
        from    ResultView rv2
        where   SubjectID = rv1.SubjectID
        order by
                total desc
        limit   2
        )

此查询通过连接三列来构造单列主键。如果你有一个真正的主键(比如ResultViewID),你可以用它代替SubjectId || '-' || StudentId || '-' || LevelId

Example at SQL Fiddle.

【讨论】:

感谢您的回答,但我得到了不同的结果。我上面发布的示例是我的问题的简化版本,也许这就是原因。我将发布更详细的版本。我从中选择的表实际上是一个视图,它通过一个共同的 id 连接两个表。如果我想根据 levelid 选择这个结果,我应该把where 子句放在哪里?

以上是关于从每组 sqlite 中选择前 n 条记录的主要内容,如果未能解决你的问题,请参考以下文章

优化获取每组前 n 条记录的方法

获取每组分组结果的前 n 条记录

获取每组分组结果的前 n 条记录

从每组中的 3 个表中选择 sql 中具有最新日期的行

从每组的第一行和最后一行获取值

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