【问题标题】:Combining window functions and conditions结合窗口函数和条件
【发布时间】:2018-09-06 01:32:56
【问题描述】:

考虑经典的学生和班级多对多关系,其中一个学生可以参加多个班级,而一个班级包含多个学生。

CREATE TABLE students(
  id serial PRIMARY KEY,
  name text,
  gender text NOT NULL
);

CREATE TABLE schools(
  id serial PRIMARY KEY,
  name text,
);

CREATE TABLE classes(
  id serial PRIMARY KEY,
  name text,
  school_id integer NOT NULL REFERENCES schools (id)
);

CREATE TABLE students_classes(
  id serial PRIMARY KEY,
  class_id integer NOT NULL REFERENCES classes (id),
  student_id integer NOT NULL REFERENCES students (id),
);

总体查询要大得多 - 考虑到学校和其他因素会增加问题的复杂性。所以我需要使用窗口函数来获取total_students之类的东西。

我想要一个查询来获取所有课程、该课程注册的学生总数、注册的男生人数和女生人数。

class_id | n_students | n_guys | n_girls
____________________________________________
         |            |        |

到目前为止我有以下,我可以得到一些帮助的男孩和女孩的数量吗?

SELECT 
  school_id,
  w.class_id,
  w.n_students,
  w.n_guys,
  w.n_girls
FROM schools
JOIN classes ON classes.school_id = schools.id
JOIN (
    c.id AS class_id,
    COUNT(*) OVER (PARTITION BY sc.class_id) AS n_students,
    {Something} AS n_guys,
    {Something} AS n_girls
  FROM students_classes AS sc
  JOIN classes AS c ON sc.class_id = c.id
) as w ON w.class_id = classes.id
WHERE school_id = 81;

【问题讨论】:

    标签: sql postgresql window-functions


    【解决方案1】:

    这个可以用,不用windows/analytic函数

    malefemale 更改为students.gender 列的文本值

    SELECT 
      s.school_id,
      c.class_id,
      COUNT(*) AS n_students,
      SUM(CASE WHEN st.gender = 'male' THEN 1 ELSE 0 END) AS n_guys,
      SUM(CASE WHEN st.gender = 'female' THEN 1 ELSE 0 END) AS n_girls
    FROM schools s
    INNER JOIN classes c
    ON c.school_id = schools.id
    INNER JOIN students_classes sc
    ON sc.class_id = classes.id
    INNER JOIN students st
    ON st.id = sc.student_id
    WHERE s.school_id = 81
    GROUP BY s.school_id, c.class_id
    ORDER BY s.school_id, c.class_id;
    

    【讨论】:

      【解决方案2】:

      因为您只使用id,所以不需要schools 表。所以,这个查询基本上是带有条件聚合的joins:

      select c.school_id, c.id as class_id,
             count(*) AS n_students,
             sum( (st.gender = 'male')::int ) AS n_guys,
             sum( (st.gender = 'female')::int ) AS n_girls
      from classes c join
           students_classes sc
           on sc.class_id = c.id join
           students st
           on st.id = sc.student_id
      where c.school_id = 81
      group by c.school_id, c.id
      order by c.school_id, c.id;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-12
        • 2016-02-11
        • 2021-10-25
        • 1970-01-01
        • 1970-01-01
        • 2018-01-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多