复杂的表连接

时间:2014-03-12 23:50:41

标签: sql sql-server tsql ms-access ms-access-2010

我认为我对桌面连接有很好的把握但是这里有一个我无法弄清楚的问题。

我正在努力跟踪学生在特定课程上取得的进展。在进一步资格认证之前,有些学生需要填写完整的课程清单。

表格(简化):

students
--------
id INT PRIMARY KEY
name VARCHAR(50)

student_courses
---------------
student_id INT PRIMARY KEY
course_id TINYINT PRIMARY KEY
course_status TINYINT (Not done, Started, Completed)
steps_done TINYINT
total_steps TINYINT
date_created DATETIME
date_modified DATETIME

courses
-------
id TINYINT PRIMARY KEY
name VARCHAR(50)

我想在courses表格中插入必修课程列表,例如5个不同的课程,然后选择一个特定的学生并获取所需课程的列表,是否存在一行当然是在student_courses表中。

我想我可以在courses表格中为每个学生插入student_courses表格中的所有行,但我不希望这样,因为并非所有学生都需要这些课程。如果以后再添加新课程该怎么办呢?

我只想要一个类似这样的结果:

students table:

id  name
--- ------------------
1   George Smith
2   Dana Jones
3   Maria Cobblestone

SELECT * FROM students (JOIN bla bla bla - this is the point where I'm lost...)
WHERE students.id = 1

Result:

id  name                course_id  courses.name  course_status  steps_done
--- ------------------  ---------  ------------  -------------  ----------
1   George Smith        1          Botany        Not started    0
1   George Smith        2          Biology       NULL           NULL
1   George Smith        3          Physics       NULL           NULL
1   George Smith        4          Algebra       Completed      34
1   George Smith        5          Sewing        Started        2

如果course_statussteps_doneNULL,则表示此学生在student_courses表中没有针对此课程的行。

然后在MS Access(或其他系统)中使用此功能,并在student_courses字段中输入值后自动将行插入NULL表。

2 个答案:

答案 0 :(得分:1)

您不能只使用外部联接来执行此操作,您需要先创建一个您感兴趣的所有学生/班级组合的列表,然后在{{1}中使用该列表}。可以使用LEFT JOIN

在cte /子查询中完成
CROSS JOIN

如果需要在Access中完成,也可以使用子查询(在Access中语法不是100%):

;WITH cte AS (SELECT DISTINCT s.id Student_ID
                             ,s.name
                             ,c.id Course_ID
                             ,c.name Class_Name
              FROM Students s
              CROSS JOIN Courses c)
SELECT cte.*,sc.status
FROM cte
LEFT JOIN student_courses sc
  ON cte.course_id = sc.course_id

演示:SQL Fiddle

答案 1 :(得分:1)

你想要一个左外连接。第一个表来自courses表,用于所需的课程(在where子句中定义)。

select s.id, s.name, c.id, c.name, c.course_status, c.steps_done
from (courses as c left join
      student_courses as sc
      on sc.course_id = c.id and
         sc.student_id = 1
     ) left join
     students as s
     on sc.student_id = s.id
where c.id in (<list of required courses>)
order by s.id, c.id;

我想我已经拥有了所有&#34; Access&#34; isms。

实际上,当他/她错过课程时,上述内容将缺少学生姓名。以下更正确:

select s.id, s.name, c.id, c.name, c.course_status, c.steps_done
from (courses as c left join
      student_courses as sc
      on sc.course_id = c.id and
         sc.student_id = 1
     ) cross join
     students as s
     on s.id = 1
where c.id in (<list of required courses>)
order by s.id, c.id;