postgresql加入混乱

时间:2016-04-25 07:00:47

标签: sql postgresql

我试图让这个陈述发挥作用。但我无法弄清楚。

  
      
  1. 列出从未参加过数据库课程的学生的姓名。
  2.   

我有这个:

select distinct s1.name, e1.section_id
from students s1
    inner join enrollment e1 on e1.student_id = s1.id
where e1.course_id != 12

但这并没有删除那个参加该部分的学生,所以我被卡住了。

数据库看起来像(我很抱歉,我不知道如何将数据库插入此处)

table students (
    id              integer primary key,
    name            varchar(255),
    graduation_date date,
    major_id        integer references departments(id)
);

insert into students (id, name, graduation_date, major_id) values
    (1, 'Joe', null, 10);
insert into students (id, name, graduation_date, major_id) values
    (2, 'Amy', '2009-04-22', 20);
insert into students (id, name, graduation_date, major_id) values
    (3, 'Max', null, 10);


create table courses (
    id              integer primary key,
    title           varchar(255),
    units           integer,
    department_id   integer references departments(id)
);

insert into courses (id, title, units, department_id) values
    (12, 'Databases', 4, 10);
insert into courses (id, title, units, department_id) values
    (22, 'Compilers', 4, 10);
insert into courses (id, title, units, department_id) values
    (32, 'Calculus 1', 4, 20);

create table sections (
    id              integer primary key,
    course_id       integer not null references courses(id),
    instructor_id   integer references faculty(id),
    year            integer
);

insert into sections (id, course_id, instructor_id, year) values
    (12, 12, 6, 2007);
insert into sections (id, course_id, instructor_id, year) values
    (13, 12, 1, 2008);
insert into sections (id, course_id, instructor_id, year) values
    (14, 22, 1, 2008);
insert into sections (id, course_id, instructor_id, year) values
    (23, 12, 6, 2009);

create table enrollment (
    id          integer primary key,
    student_id  integer not null references students(id),
    section_id  integer not null references sections(id),
    grade_id    integer references grades(id)
);

insert into enrollment (id, student_id, section_id, grade_id) values
    (14, 1, 12, 8);
insert into enrollment (id, student_id, section_id, grade_id) values
    (15, 1, 13, 3);
insert into enrollment (id, student_id, section_id, grade_id) values
    (16, 1, 14, 5);
insert into enrollment (id, student_id, section_id, grade_id) values
    (17, 1, 32, 1);
insert into enrollment (id, student_id, section_id, grade_id) values
    (18, 1, 34, 2);
insert into enrollment (id, student_id, section_id, grade_id) values
    (19, 1, 53, 13);
insert into enrollment (id, student_id, section_id, grade_id) values
    (24, 3, 12, 2);
insert into enrollment (id, student_id, section_id, grade_id) values
    (25, 3, 14, 5);
insert into enrollment (id, student_id, section_id, grade_id) values
    (26, 3, 32, 1);
insert into enrollment (id, student_id, section_id, grade_id) values
    (27, 3, 34, 2);
insert into enrollment (id, student_id, section_id, grade_id) values
    (28, 3, 54, 7);
insert into enrollment (id, student_id, section_id, grade_id) values
    (34, 2, 43, 3);
insert into enrollment (id, student_id, section_id, grade_id) values

2 个答案:

答案 0 :(得分:2)

不,不要加入所有内容,然后尝试使用DISTINCT进行清理。这是一个糟糕的方法。而是先考虑一下你想要选择的内容。然后逐步编写查询。

“从未上过课程数据库的学生”是

  • 所有学生除了那些参加过数据库课程
  • 的学生
  • 所有不在参加课程数据库的学生
  • 的学生
  • 不存在数据库课程的所有学生

我突出了所需的关键字。所以你有三个选择:

  • 使用EXCEPT
  • 撰写查询
  • 使用NOT IN
  • 撰写查询
  • 使用NOT EXISTS
  • 撰写查询

如果您还有其他问题,请尝试这些并返回此处。

更新:现在你解决了它(甚至接受了我的回答:-),这里有一些编写查询的方法:

使用IN子句进行查询:

select name 
from students 
where id not in 
(
  select student_id 
  from enrollment 
  where section_id in 
  (
    select id 
    from sections 
    where course_id = (select id from courses where title = 'Databases')
  )
); 

使用EXISTS子句查询:

select name 
from students 
where not exists
(
  select * 
  from enrollment 
  where section_id in 
  (
    select id 
    from sections 
    where course_id = (select id from courses where title = 'Databases')
  )
  and student_id = students.id
); 

使用EXCEPT进行查询(这里的解决方案不是很好,因为它会两次查询学生表,但有时候EXCEPT是解决问题的直接方法)。我在这里使用子查询而不是WHERE students.id IN (...),只是为了展示技术。

select name 
from students 
join
(
  select id
  from students
  except
  select student_id 
  from enrollment 
  where section_id in 
  (
    select id 
    from sections 
    where course_id = (select id from courses where title = 'Databases')
  )
) found_students on found_students.id = students.id; 

使用COUNT和HAVING查询,看起来非常紧凑。然而,它更容易出错。有一点不是混淆外连接中的ON和WHERE,另一种是计算正确的列。我们必须确保计算一个不可为空的表格部分字段,因此我们确信学生的所有注册都不符合实际的数据库部分。

select s.id, s.name
from students s
left join enrollment e on e.student_id = s.id
left join sections s on s.id = e.section_id 
                     and s.course_id = (select id from courses where title = 'Databases')
group by s.id, s.name
having count(s.id) = 0;

答案 1 :(得分:1)

我认为上面的查询使主题变得复杂,所以我添加了自己的。

SELECT s.*
FROM students s
   LEFT JOIN (enrollment e
       INNER JOIN sections se
         ON se.id = e.section_id
       INNER JOIN courses c
         ON c.id = se.course_id AND c.title = 'Databases')
     ON s.id = e.student_id
WHERE
  e.id IS NULL