如何在SQLite表中基于总标记检索排名

时间:2015-02-07 00:45:56

标签: sql sqlite

说我有这样一张桌子:

 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并根据总和(ca1 + ca2 +考试)为每个学生分配一个等级,如下所示:

 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。

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

制作表格:

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;

答案 1 :(得分:1)

这样的事情可能是:

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;

答案 2 :(得分:1)

根据我的标准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)构造来添加总和。这就是提出问题的方式,要求系统做更少的工作(只有一次总结)。当然,添加是可交换的,但我不会依赖查询优化器来注意。