如何选择每组的前N行?

时间:2013-08-01 10:49:16

标签: sql sqlite greatest-n-per-group limit-per-group

我有两个这样的SQLite表:

 AuthorId | AuthorName
----------------------
 1        | Alice
 2        | Bob
 3        | Carol
 ...      | ....


 BookId | AuthorId | Title
----------------------------------
 1      | 1        | aaa1
 2      | 1        | aaa2
 3      | 1        | aaa3
 4      | 2        | ddd1
 5      | 2        | ddd2
 ...    | ...      | ...
 19     | 3        | fff1
 20     | 3        | fff2
 21     | 3        | fff3
 22     | 3        | fff4

我想创建一个SELECT查询,它将返回每个AuthorId的前N行(例如两行),按标题排序(“选择每个作者的前两本书”)。

示例输出:

 BookId |  AuthorId | AuthorName | Title
------------------------------------------
 1      |  1        |   Alice    | aaa1
 2      |  1        |   Alice    | aaa1
 4      |  2        |   Bob      | ddd1
 5      |  2        |   Bob      | ddd2
 19     |  3        |   Carol    | fff1
 20     |  3        |   Carol    | fff2

如何构建此查询?

(是的,我发现了一个类似的话题,我知道如何只返回一行(第一行或最高行)。问题在于两行。)

3 个答案:

答案 0 :(得分:16)

您可以使用相关子查询进行计数:

SELECT b.BookId, a.AuthorId, a.AuthorName, b.Title
FROM Author a join
     Book b
     on a.AuthorId = b.AuthorId
where (select count(*)
       from book b2
       where b2.bookId <= b.BookId and b2.AuthorId = b.AuthorId
      ) <= 2;

对于小型数据库,这应该没问题。如果您在Book(AuthorId, BookId)上创建复合索引,那么这将有助于查询。

答案 1 :(得分:14)

还有另一种变体:

SELECT * FROM (
    SELECT * FROM BOOK, AUTHOR
    WHERE BOOK.AUTHORID = AUTHOR.AUTHORID
) T1
WHERE T1.BOOKID IN (
    SELECT T2.BOOKID FROM BOOK T2
    WHERE T2.AUTHORID = T1.AUTHORID
    ORDER BY T2.BOOKTITLE
    LIMIT 2
)
ORDER BY T1.BOOKTITLE

答案 2 :(得分:-1)

你走了。可能为时已晚,但我刚看到这篇文章。您可以更改&lt; = 2以匹配您需要的n。

SELECT 
 a.authorid,
 a.authorname,
 b.bookid,
 b.booktitle
FROM author a
JOIN book b ON b.authorid = b.authorid
QUALIFY ROW_NUMBER() OVER (PARTITION BY a.authorid
ORDER BY   b.booktitle ASC) <=2