Объединение оконных функций и условий - PullRequest
0 голосов
/ 06 сентября 2018

Рассмотрим классические отношения «ученик и классы многие-много», когда ученик может посещать несколько классов, а класс состоит из нескольких учеников.

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;

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Поскольку вы просто используете id, вам не нужна таблица schools. Итак, этот запрос в основном join с условной агрегацией:

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;
0 голосов
/ 06 сентября 2018

Вы можете использовать это, нет необходимости использовать окна / аналитические функции

Измените 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;
...