如何从SQLITE中选出每个团队的前N名获胜者?

时间:2016-07-26 09:03:08

标签: sqlite limit-per-group

我有一个像这样的sqlite3表:

sqlite> select * from scores;
team        Name        score
----------  ---------   ----------
A           Name1       93
A           Name2       96
A           Name3       78
A           Name4       82
B           Name5       83
B           Name6       30
B           Name7       99
B           Name8       71
B           Name8A      45
B           Name8C      70
c           Name9       87
c           Name10      87
c           Name11      81
c           Name12      71
c           Name13      91

有很多团队(大约30个团队),每个团队都有很多成员(实际记录超过10,000个)。我只想得到每个团队的前N名获胜者(为了简化,在这个例子中N = 3):

A     Name2   96
A     Name1   93
A     Name4   82
B     Name7   99
B     Name5   83
B     Name8   71
C     Name13  91
C     Name9   87
C     Name10  87

并且他们按照他们在相同团队中的得分进行排名。

如何使用sqlite3查询获得此结果?谁能提供一些线索? 非常感谢。

顺便说一下,'姓名'字段非唯一,只有(团队,名称)是UNIQUE,这意味着同一名称可以出现在不同的团队中。

3 个答案:

答案 0 :(得分:0)

你可以试试这个

set @currcount=0,@currvalue='', @N=4;
SELECT team, Name, score FROM ( SELECT team, Name, score, @currcount :=    
IF(@currvalue = team, @currcount + 1, 1) as rank, @currvalue := team FROM 
scores ORDER BY team DESC) as what WHERE rank<@N order by team asc, score desc

答案 1 :(得分:0)

根据Question: how to select first N row of each group?,Gordon Linoff的方法,我想出了这段代码:

select * from dayobs a 
     where a.rowid in 
     (select b.rowid from dayobs b where b.station==a.station order by b.rain desc limit 5);

它有效,但非常慢,sqlite给每条记录超过1分钟!此查询大约需要半小时才能完成。显然,这不可能在实际工作中发生。我认为必须有一些方法来提高效率。

答案 2 :(得分:0)

我们可以从表中选择结果集,而不是从scores表中选择每个团队的前N个结果,其中包含每个团队的前N个结果。

让我们将所需数据称为leaderboard,其结构等于scores

我们将插入score的数据复制到leaderboard。然后我们只保留leaderboard中每个团队的最佳N分数,删除任何不够高的分数。为了做到这一点,我们需要一个触发器如下:

CREATE TRIGGER "update_top_scores"
AFTER INSERT ON scores  
BEGIN
    -- Add the record to leaderboard
    INSERT INTO leaderboard (team, name, score) VALUES (NEW.team, NEW.name, NEW.score);
    -- only keep the top 30 records of each teams 
    DELETE FROM leaderboard WHERE team = NEW.team AND name NOT IN (SELECT name FROM leaderboard WHERE team = NEW.team ORDER BY score DESC LIMIT 30);

END

现在我们可以使用一个简单的查询获得每个团队的前N个分数

SELECT * FROM leaderboard;

假设您不希望在db文件中有新表或触发器,我建议您执行以下操作

  1. 创建新表leaderboarddummy_scores
  2. dummy_scores
  3. 创建触发器
  4. 使用INSERT INTO ... SELECT语句将数据从score复制到dummy_score,这也会激活触发器
  5. SELECT * FROM leaderboard
  6. 获取结果
  7. drop leaderboarddummy_scores和db file
  8. 中的触发器

    现在您拥有原始数据库文件以及所需的结果。