组合 window 个函数和条件
Combining window functions and conditions
考虑 classic Student 和 类 多对多关系,其中一个学生可以参加多个 classes 并且 class 包含多个学生。
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),
);
总体查询要大得多 - 考虑到学校和其他因素会增加问题的复杂性。所以我需要使用 window 函数来获取 total_students
.
之类的东西
我想要一个查询来获取所有 classes,其中注册的学生总数 class,注册的男生人数和女生人数。
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;
你可以使用这个,不需要使用 windows/analytic 函数
将 male
和 female
更改为 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;
因为您只是使用 id
,所以不需要 schools
table。所以,这个查询基本上是 join
s 条件聚合:
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;
考虑 classic Student 和 类 多对多关系,其中一个学生可以参加多个 classes 并且 class 包含多个学生。
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),
);
总体查询要大得多 - 考虑到学校和其他因素会增加问题的复杂性。所以我需要使用 window 函数来获取 total_students
.
我想要一个查询来获取所有 classes,其中注册的学生总数 class,注册的男生人数和女生人数。
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;
你可以使用这个,不需要使用 windows/analytic 函数
将 male
和 female
更改为 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;
因为您只是使用 id
,所以不需要 schools
table。所以,这个查询基本上是 join
s 条件聚合:
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;