自连接

时间:2025-04-15 07:54:47

9.3  表的连接类型

9.3.1  自连接

自连接是指表与其自身进行连接,这就需要用到前面介绍的表别名。下面通过一个具体实例来讲解自连接的应用。

实例5  自连接的使用方法

查询成绩中存在不及格课程的学生的姓名、所在系、所有的课程及成绩信息。如果采用前面介绍的SELECT语句查询方法,该实例的实现要分为两步。

1.查询存在不及格课程的学生的学号

之所以查询学号,是因为学号是学生的惟一标识信息。代码:

SELECT   DISTINCT  SNO
FROM   STUDENT
WHERE  MARK<60

运行结果如图9.5所示。

 
图9.5  不及格课程学生的学号

注意 因为可能有的学生的不及格课程多于1门,因此在SELECT子句中使用了DISTINCT关键词,去除重复的学号。

2.根据学号查询相关信息

根据查询的学号结果,查询这些学号的学生的姓名、所在系、所有所修课程及成绩信息。代码:

SELECT   SNAME, DNAME, CNO, MARK
FROM   STUDENT
WHERE  SNO IN (‘9702’,’9703’,’9705’)
ORDER BY  SNAME

运行结果如图9.6所示。

 
图9.6  根据学号查询的相关信息

而如果采用表的自连接,只要通过一步查询就可以实现该实例。代码:

SELECT   DISTINCT , , , 
FROM   STUDENT AS S1, STUDENT AS S2
WHERE   =
AND   S2. MARK<60
ORDER BY  

运行结果如图9.7所示。

代码中,FROM子句中的两个表实际上都是表STUDENT。为了独立地使用它们,采用上节介绍的表别名方法,分别为其取别名S1和S2。这样就可以在WHERE子句中,使用S2设定分数查询条件,而在SELECT子句中,使用S1查询满足条件的结果。

需要说明一点,SELECT子句同样要有关键字DISTINCT,如果没有使用DISTINCT关键字,如下面的代码:

 
图9.7  采用表的自连接执行的查询结果

SELECT   , , , 
FROM   STUDENT AS S1, STUDENT AS S2
WHERE   =
AND   S2. MARK<60
ORDER BY  

运行结果如图9.8所示。

 
图9.8  采用表的自连接但没有去除重复记录的查询结果

可以发现,结果表中出现了重复的记录。下面分析一下代码的执行过程,从中就不难发现重复记录产生的原因。

系统首先执行FROM子句,将STUDENT表S1与它自身S2的笛卡尔积,作为中间表。实际上,该中间表的每一条记录包含两部分信息,一部分是S1的记录,一部分是S2的记录。而后执行WHERE子句,在中间表中,搜索S2中成绩低于60分的学生的记录,同时要求记录中S1与S2是同一个学生的记录即学号相同。最后执行SELECT语句,从中间表获取S1中相应的信息作为结果表。

当执行WHERE子句,从中间表中逐条搜索S2中成绩低于60分的学生的记录时,由于孙庆有两门课程不及格,所以对于每门不及格的记录都满足搜索条件,因此导致了从S1得到的信息中出现了重复记录。

简单来说,中间表是没有重复记录的,但是S1部分字段是有重复的,而结果集提取的只是S1部分的字段,因此就有可能有重复记录。