【问题标题】:How to Retrieve Rank Based on Total Mark in SQLite Table如何根据 SQLite 表中的总分检索排名
【发布时间】:2018-03-19 13:32:26
【问题描述】:

假设我有一张这样的桌子:

 S_id  |ca1 |ca2 |exam
  1    | 08 | 12 | 35
  1    | 02 | 14 | 32
  1    | 08 | 12 | 20
  2    | 03 | 11 | 55
  2    | 09 | 18 | 45
  2    | 10 | 12 | 35
  3    | 07 | 12 | 35
  3    | 04 | 14 | 37
  3    | 09 | 15 | 32
  4    | 03 | 11 | 55
  4    | 09 | 18 | 45
  4    | 10 | 12 | 35
  5    | 10 | 12 | 35
  5    | 07 | 12 | 35
  5    | 09 | 18 | 45

我想选择 S_id、total 并根据 sum(ca1+ca2+exam) 为每个学生分配一个排名,如下所示:

 S_id |total|rank
   1  | 158 | 5
   2  | 198 | 1
   3  | 165 | 4
   4  | 198 | 1
   5  | 183 | 3

如果总数相同,比如S_id 2 和S_id 4 排名为 1,我希望排名跳到 3。

感谢您的帮助。

【问题讨论】:

  • sqlite是否支持Rank()解析函数
  • SQLite 不支持 Rank() 但我希望 Rank 列作为别名

标签: sql sqlite


【解决方案1】:

制作桌子:

sqlite> create table t (S_id, ca1, ca2, exam);
sqlite> insert into t values 
   ...> ( 1 , 08 , 12 , 35 ),
   ...> ( 1 , 02 , 14 , 32 ),
   ...> ( 1 , 08 , 12 , 20 ),
   ...> ( 2 , 03 , 11 , 55 ),
   ...> ( 2 , 09 , 18 , 45 ),
   ...> ( 2 , 10 , 12 , 35 ),
   ...> ( 3 , 07 , 12 , 35 ),
   ...> ( 3 , 04 , 14 , 37 ),
   ...> ( 3 , 09 , 15 , 32 ),
   ...> ( 4 , 03 , 11 , 55 ),
   ...> ( 4 , 09 , 18 , 45 ),
   ...> ( 4 , 10 , 12 , 35 ),
   ...> ( 5 , 10 , 12 , 35 ),
   ...> ( 5 , 07 , 12 , 35 ),
   ...> ( 5 , 09 , 18 , 45 );

用总分制作一个临时表:

sqlite> create temp table tt
        as select S_id, sum(ca1) + sum(ca2) + sum(exam) as total
        from t group by S_id;

使用临时表计算排名:

sqlite> select s.S_id, s.total,
          (select count(*)+1 from tt as r where r.total > s.total) as rank
          from tt as s;
1|143|5
2|198|1
3|165|4
4|198|1
5|183|3

删除临时表:

sqlite> drop table tt;

附录

随着最近对 SQLite 的更改 (2015-02-09),此公式现在可以使用:

with tt (S_id, total) as 
   (select S_id, sum(ca1 + ca2 + exam) as total from t group by S_id)
select s.S_id, s.total,
       (select count(*)+1 from tt as r where r.total > s.total) as rank
   from tt as s;

【讨论】:

  • 非常感谢,它就像魔术一样工作,但是没有临时表有没有其他方法可以实现它
【解决方案2】:

可能是这样的:

with tt(S_id,total) as (
  select S_id, sum(ca1) + sum(ca2) + sum(exam)
    from t
    group by S_id
  union
  select null, 0
  )
  select s.S_id,
         s.total,
         (select count(*)+1
            from tt as r
            where r.total > s.total) as rank
     from tt as s
     where S_id is not null;

【讨论】:

  • 非常感谢 tonypdmtr,这正是我想要的
  • 正如 Doug Currie 更新后的帖子中提到的,最新的 SQLite3 修复了 SQLite3 中一个明显长期存在的错误,因此现在无需使用带有 NULL 的 UNION 技巧来绕过该错误。
【解决方案3】:

根据我的标准 Rank Rows 答案,使用自联接:

with tt (S_id, total) as
   (select S_id, sum(ca1 + ca2 + exam) as total
       from t group by S_id)
select S.S_id, S.total, 1+count(lesser.total) as RANK
        from tt as S
        left join tt as lesser
        on   S.total < lesser.total
        group by S.S_id, S.total
        order by S.total desc;
S_id        total       RANK      
----------  ----------  ----------
2           198         1         
4           198         1         
5           183         3         
3           165         4         
1           143         5         

您不需要 CTE;您可以改用子查询,但您必须重复它。

在 SELECT 子句中使用 SELECT 子句来生成列(如其他地方所建议的)是 AFAIK 非标准的。自联接是标准的,查询计划器应该更容易优化(如果只是出于这个原因)。此外,上述查询不会处理数据:它不会向 CTE 添加一行,只是为了在主查询中将其删除。

我更喜欢 sum(ca1 + ca2 + exam) 结构而不是总和。这就是问题的提出方式,它要求系统做更少的工作(只有一个总和)。当然,加法是可交换的,但我不会依赖查询优化器来注意。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 2017-05-07
    • 1970-01-01
    • 2017-01-25
    • 2013-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多