【问题标题】:postgres use of rank functionpostgres对rank函数的使用
【发布时间】:2019-08-28 18:16:38
【问题描述】:

我是 Sql 查询的新手。我需要构建一个查询,该查询将根据学生获得 100% 的测试次数除以他参加的测试总数来对学生进行排名,并仅考虑 10 天前的测试。这是我的表结构。

CREATE TABLE student(
id serial NOT NULL,student_email varchar NULL,
student_name varchar NULL,
test_subject varchar NULL,
total_question varchar NULL,
total_passed varchar NULL,
total_failed varchar NULL,
total_skipped varchar NULL,
test_time timestamp NULL,
CONSTRAINT student PRIMARY KEY (id));

如果学生的 total_failed 或 total_skipped 不为 0,则该测试不被视为 100%。

样本数据会是这样的

1   j@b.com john    maths   10  10  0   0   2019-08-20 21:00:00
2   j@b.com john    maths   10  10  0   0   2019-08-19 21:00:00
3   j@b.com john    maths   10  09  1   0   2019-08-18 21:00:00
4   j@b.com john    english 10  10  0   0   2019-08-20 21:00:00
5   j@b.com john    english 10  10  0   0   2019-08-19 21:00:00
6   j@b.com john    english 10  09  0   1   2019-08-20 21:00:00
7   p@b.com paul    maths   10  10  0   0   2019-08-20 21:00:00
8   p@b.com paul    maths   10  10  0   0   2019-08-19 21:00:00
9   p@b.com paul    maths   10  10  0   0   2019-08-18 21:00:00
10  k@b.com koki    maths   10  10  0   0   2019-06-20 21:00:00
11  k@b.com koki    english 10  10  0   0   2019-06-20 21:00:00
12  k@b.com koki    science 10  10  0   0   2019-08-20 21:00:00
13  k@b.com koki    maths   10  08  2   0   2019-08-20 21:00:00
14  k@b.com koki    english 10  10  0   0   2019-08-20 21:00:00

从上面的数据集中,我只需要考虑那些在 10 天内的数据,并根据每个不同的 subject_name,student 的测试总数除以 100% 的测试总数来给出“排名”。 上述数据集的输出将是

koki    science 100%   k@b.com
koki    english 100%   k@b.com
paul    maths   100%   p@b.com
john    maths   66.6%  j@b.com
john    english 66.6%  j@b.com
koki    science 0%     k@b.com

任何帮助表示赞赏

【问题讨论】:

    标签: sql database postgresql rank


    【解决方案1】:

    当我

    • 翻译你对rank的定义:

      100% 的测试总数除以测试总数

      作为

      COUNT(*) FILTER (WHERE total_passed = total_question) / COUNT(*)::real
      
    • 并应用过去 10 天的过滤器:

      test_time > CURRENT_DATE - interval '10 days'
      

    我最终得到以下查询

    SELECT  
      student_name
    , test_subject
    , COUNT(*) FILTER (WHERE total_passed = total_question) / COUNT(*)::real student_rank
    
    FROM student 
    WHERE test_time > CURRENT_DATE - interval '10 days' 
    GROUP BY 1, 2 
    ORDER BY 3 desc;
    

    我得到了想要的输出:

     student_name | test_subject |   student_rank
    --------------+--------------+-------------------
     paul         | maths        |                 1
     koki         | english      |                 1
     koki         | science      |                 1
     john         | maths        | 0.666666666666667
     john         | english      | 0.666666666666667
     koki         | maths        |                 0
    (6 rows)
    

    【讨论】:

      【解决方案2】:

      您可以使用条件聚合。在这种情况下,avg() 应该可以工作:

      select student_name, test_subject,
             avg( (total_failed + total_skipped = 0)::int ) as ratio_passed
      from t
      where test_time > now() - interval 10 day
      group by student_name, test_subject;
      

      【讨论】:

      • 运行此 SQL 时遇到几个错误 错误 [42601]:错误:“10”位置或附近的语法错误:161 错误:“10”位置或附近的语法错误:161 错误:语法“10”位置或附近的错误:161
      • 如果我删除 10 天过滤器 SQL 错误 [42883]:错误:运算符不存在:字符变化 + 字符变化提示:没有运算符与给定名称和参数类型匹配。您可能需要添加显式类型转换。位置:54 错误:运算符不存在:字符变化 + 字符变化提示:没有运算符匹配给定的名称和参数类型。您可能需要添加显式类型转换错误:运算符不存在:字符变化 + 字符变化提示:没有运算符与给定的名称和参数类型匹配。您可能需要添加显式类型转换。
      • total_failed 和 total_skipped 是 varchar
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-08
      • 1970-01-01
      • 2017-07-21
      • 2015-11-28
      • 2017-07-25
      • 2023-04-03
      • 1970-01-01
      相关资源
      最近更新 更多