如何对多个表使用SQL Join操作

时间:2013-10-30 10:13:55

标签: sql sql-server join

假设有7个这样的表:

class_teacher_lesson

class_teacher_lession_ID, class_ID, teacher_ID, lesson_ID

class_ID, class

教师

teacher_ID, teacher

lesson_ID, lesson

学生

student_ID, class_ID, ..., ....

survey_answer

survey_answer_ID, survey_question_ID, class_teacher_lession_ID, survey_answer

survey_question

survey_question_ID, survey_question, 

结果应该是这样的:

我将通过循环得到这个:

课程数学:

survey_question (where teacher_id = 11 and lesson_id = 13):
Total Students            Total Students Answered Survey         survey_answer AVG
     155                                45                              79%

survey_question 2 (where teacher_id = 11 and lesson_id = 13):
Total Students            Total Students Answered Survey         survey_answer AVG
     155                                99                              87%

课程英语:

survey_question (where teacher_id = 11 and lesson_id = 15):
Total Students            Total Students Answered Survey         survey_answer AVG
     90                                20                              50%

survey_question 2 (where teacher_id = 11 and lesson_id = 15):
Total Students            Total Students Answered Survey         survey_answer AVG
     90                                25                              34%

到目前为止,我已经尝试过这个:

SELECT teacher AS 'Teacher', class AS 'Class', lesson AS 'Lesson',
COUNT(student_ID) AS 'Number of students',
COUNT(enquete_antwoord_ID) AS 'Total students answered survey', 
enquete_vraag AS 'Survey Question'
FROM Teacher
LEFT JOIN class_teacher_lesson
ON teacher.teacher_ID = class_teacher_lesson.teacher_ID
LEFT JOIN lesson
ON class_teacher_lesson.class_ID = lesson.lesson_ID
LEFT JOIN class
ON class_teacher_lesson.class_ID = class.class_ID
LEFT JOIN student
ON class.class_ID = student.class_ID
LEFT JOIN survey_answer
ON class_teacher_lesson.class_teacher_lesson_ID = 
survey_answer.class_teacher_lesson
LEFT JOIN survey_question
ON survey_answer.survey_question_ID = survey_question.survey_question_ID
WHERE teacher.teacher_ID = '1158' AND lesson.lesson_ID = '449'
GROUP BY class.class, lesson.lesson, teacher.teacher,
survey_answer.survey_answer, survey_question

结果如下:

Teacher:  Class:   Lesson:  Number of students:  Filled in:    Survey_question:
t1        c1       math     54                   54            question1?
t1        c1       math     24                   0             NULL
t1        c1       math     22                   0             NULL

结果应该是这样的:

Teacher:  Class:   Lesson:  Number of students:  Filled in:    Survey_question:
t1        c1       math     90                   54            question1?

2 个答案:

答案 0 :(得分:0)

select survey_question, teacher_id, lesson_id , 
       count(1) as Total_student_answer_survey, 
       (select count(1) from student) as total_student,   
       count(1)/(select count(1) from student) * 100 as survey_percentage
from survey_answer sa
inner join survey_question sq 
    on sa.survey_question_id = sq.survey_question_id
inner join class_teacher_lesson ctl 
    on sa.class_teacher_lesson_id = ctl.class_teacher_lesson_id
group by teacher_id, lesson_id, survey_question_id

答案 1 :(得分:0)

我假设您的选择中的enquete_vraag和您问题中的survey_question实际上是同一列,而这只是翻译中遗漏的内容(否则查询将无法选择列不在小组中。)

在这种情况下,您实际需要做的就是从group by子句中删除survey_answer.survey_answer(您也可以将一些左连接更改为内部,这可以提高性能。)。

SELECT  teacher AS 'Teacher', 
        class AS 'Class', 
        lesson AS 'Lesson',
        COUNT(student_ID) AS 'Number of students',
        COUNT(enquete_antwoord_ID) AS 'Total students answered survey', 
        enquete_vraag AS 'Survey Question',
        100.0 * COUNT(enquete_antwoord_ID) / COUNT(student_ID) AS 'survey_answer AVG'
FROM    Teacher
        INNER JOIN class_teacher_lesson
            ON teacher.teacher_ID = class_teacher_lesson.teacher_ID
        INNER JOIN lesson
            ON class_teacher_lesson.class_ID = lesson.lesson_ID
        INNER JOIN class
            ON class_teacher_lesson.class_ID = class.class_ID
        LEFT JOIN student
            ON class.class_ID = student.class_ID
        LEFT JOIN survey_answer
            ON class_teacher_lesson.class_teacher_lesson_ID = survey_answer.class_teacher_lesson
        LEFT JOIN survey_question
            ON survey_answer.survey_question_ID = survey_question.survey_question_ID
WHERE   teacher.teacher_ID = '1158' 
AND     lesson.lesson_ID = '449'
GROUP BY class.class, lesson.lesson, teacher.teacher, survey_question

然而(虽然这完全是主观的)我建议使用表别名清理查询,也不建议使用单引号来识别列别名(以避免与文字混淆),并且(这更加主观)我添加了SQL-Server特定的Alias = Column_name语法,我个人认为这种语法更具可读性(Perhaps some more eloquent reasons to switch are presented here by Aaron Bertrand)。

SELECT  t.teacher, 
        c.class, 
        l.lesson,
        [Number of students] = COUNT(s.student_ID),
        [Total students answered survey] = COUNT(sa.enquete_antwoord_ID), 
        [Survey Question] = sq.enquete_vraag,
        [% Students Answered] = 100.0 * COUNT(sa.enquete_antwoord_ID)  / COUNT(s.student_ID)
FROM    Teacher t
        INNER JOIN class_teacher_lesson ctl
            ON t.teacher_ID = ctl.teacher_ID
        INNER JOIN lesson l
            ON ctl.class_ID = l.lesson_ID
        INNER JOIN class c
            ON ctl.class_ID = c.class_ID
        LEFT JOIN student s
            ON c.class_ID = s.class_ID
        LEFT JOIN survey_answer sa
            ON ctl.class_teacher_lesson_ID = sa.class_teacher_lesson
        LEFT JOIN survey_question sq
            ON sa.survey_question_ID = sq.survey_question_ID
WHERE   t.teacher_ID = '1158' 
AND     l.lesson_ID = '449'
GROUP BY c.class, l.lesson, t.teacher, sq.survey_question;

这两种解决方案都应该给出相同的结果,我并不想强迫我对任何人的偏好,我只是提出选择。对于您发现哪些更具可读性,这只是一个偏好问题。

修改

我认为由于将多个一对多关系加入到相同的“一个”中,您正在进行交叉加入,这导致了零调查问题。我认为将聚合移动到子查询可能会有所帮助:

SELECT  t.teacher, 
        c.class, 
        l.lesson,
        [Number of students] = ISNULL(s.Students, 0),
        [Total students answered survey] = ISNULL(sq.Answers, 0), 
        sq.SurveyQuestion,
        [% Students Answered] = 100.0 * ISNULL(sq.Answers, 0) / NULLIF(s.Students, 0)
FROM    Teacher t
        INNER JOIN class_teacher_lesson ctl
            ON t.teacher_ID = ctl.teacher_ID
        INNER JOIN lesson l
            ON ctl.class_ID = l.class_ID
        INNER JOIN class c
            ON ctl.class_ID = c.class_ID
        LEFT JOIN 
        (   SELECT  Class_ID, Students = COUNT(*)
            FROM    student s
            GROUP BY Class_ID
        ) S
            ON c.class_ID = s.class_ID
        LEFT JOIN 
        (   SELECT  sa.class_teacher_lesson_ID, 
                    sq.SurveyQuestion,
                    Answers = COUNT(*)
            FROM    survey_answer sa
                    LEFT JOIN survey_question sq
                        ON sa.survey_question_ID = sq.survey_question_ID
            GROUP BY sa.class_teacher_lesson_ID, sq.SurveyQuestion
        ) sq
            ON ctl.class_teacher_lesson_ID = sq.class_teacher_lesson_ID
WHERE   t.teacher_ID = '1158' 
AND     l.lesson_ID = '449';