3.3.2 多关系查询
找出所有教师
的姓名
,以及他们所在系
的名称
和系所在建筑的名称
考虑instructor
关系的模式,我们发现可以从dept_name
属性得到系名
,但是系所在建筑的名称是在department
关系的building
属性中给出的。
教师模式:
instructor(ID,name,dept_name,salary)
系模式:department(dept_name,building,budget)
为了回答上面的查询, instructor
关系中的每个元组必须与department
关系中的元组匹配,也就是department
在dept_name
上的取值要等于
instructor
元组在dept_name
上的取值。
如何查询
为了在SQL
中回答上述查询,我们把需要访问的关系都列在from
子句中,并在where
子句中指定匹配条件
。
对应的SQL语句
上述查询可用SQL
写为:
1 | select name, instructor.dept_name, building |
1 | mysql> select name, instructor.dept_name, building |
两个关系中的同名属性要使用关系名作为前缀
dept_name
属性既出现在instructor
关系中,也出现在department
中,所以需要使用关系名作为前缀来说明我们使用的是哪个属性
例如:instructor.dept_name
department.dept_name
不重名的属性不需要关系名作为前缀
属性name
和building
只出现在一个关系中,因而不需要把关系名作为前缀。
多个关系查询的SQL
通用形式
现在我们考虑涉及多个关系的SQL
查询的通用形式。
select from where三个子句的作用
一个SQL
查询可以包括三种类型的子句:select
子句、from
子句和where
子句。每种子句的作用如下:
select
子句用于列出查询结果中所需要的属性
。from
子句是一个查询求值中需要访问的关系列表
。where
子句是一个作用在from
子句中关系的属性上的谓词
SQL查询语句格式
一个典型的SQL
查询具有如下形式:
1 | select A1,A2,...An |
每个An
,代表一个属性,每个Rm
代表一个关系。P
是一个谓词。如果省略where
子句,则谓词P
为true
。
如何
查询运算各子句的执行顺序
尽管各子句必须以select
、from
、 where
的次序写出,但理解查询所代表运算的最容易的方式是以运算的顺序
来考察各子句:
- 首先是
from
, - 然后是
where
, - 最后是
select
。
form子句得到笛卡尔积
通过from
子句定义了一个在该子句中所列出关系上的笛卡儿积
。
它可以用集合理论来形式化地定义,但最好通过下面的迭代过程来理解,此过程可为from
子句的结果关系产生元组。
1 | for each 元组T1 in 关系R1 |
此结果关系具有来自from
子句中所有关系的所有属性。由于在关系Ri
和Rj
中可能出现相同的属性名,此时需要在属性名前加上关系名作为前缀,表示该属性来自于哪个关系。
笛卡尔积说明
instructor(ID,name,dept_name,salary)
teaches(ID,course_id,sec_id,semester,year)
关系instructor
和teaches
的笛卡儿积
的关系模式为:
1 | (instructor.ID, instructor.name, instructor.dept_name, instructor.salary teaches.ID, teaches.course_id, teaches.sec_id, teaches.semester, teaches.year) |
有了这个模式,我们可以区分出instructor.ID
和teaches.ID
。对于那些只出现在单个模式中的属性,我们通常去掉关系名前缀。这种简化并不会造成任何混淆。这样我们可以把关系模式写为
1 | (instructor.ID, name, dept_name, salary, teaches.ID, course_id, sec_id, semester, year) |
通过笛卡儿积
把来自instructor
和teaches
中相互没有关联的元组组合起来。 instructor
中的每个元组和teaches
中的所有元组都要进行组合。结果可能是一个非常庞大的关系,创建这样的笛卡儿积通常是没有意义的。
where子句限制from子句得到的笛卡尔积
where
子句中的谓词用来限制笛卡儿积所建立的组合,只留下那些对所需答案有意义的组合。
例如:
我们希望把teaches
元组只和具有相同ID
值的instructor
元组进行匹配。下面的SQL
查询满足这个条件,从这些匹配元组中输出教师名和课程标识。
1 | select name, course_id |
1 | mysql> select name, course_id |
注意上述查询只输出讲授了课程的教师,不会输出那些没有讲授任何课程的教师,可以使用一种被称作外连接
的运算,外连接将在4.1.2节讲述。
如果我们只希望找出Computer Science
系的教师名和课程标识,我们可以在where
子句中增加另外的谓词,如下所示:
1 | select name, course_id |
1 | mysql> select name, course_id |
理解SQL查询的结果应该是什么样的
通常说来,一个SQL
查询的含义可以理解如下:
- 为
from
子句中列出的关系产生笛卡儿积
。 - 在步骤1的结果上应用
where
子句中指定的谓词。 - 对于步骤2结果中的每个元组,输出
select
子句中指定的属性(或表达式的结果)。
上述步骤的顺序有助于明白一个SQL
查询的结果应该是什么样的,而不是这个结果是怎样被执行的。在SQL
的实际实现中不会执行这种形式的查询,它会通过(尽可能)只产生满足where
子句谓词的笛卡儿积元素来进行优化执行。我们在后面第12章和第13章学习那样的实现技术。
要设置合适的where
当书写查询时,需要小心设置合适的where子句条件。如果在前述SQL查询中省略where子句条件,就会输出笛卡儿积
,那是一个巨大的关系
大学数据库模式
classroom(building,room_number,capacity)
department(dept_name,building,budget)
course(course_id,title,dept_name,credits)
instructor(ID,name,dept_name,salary)
section(course_id,sec_id,semester,year,building,room_number,time_slot_id)
teaches(ID,course_id,sec_id,semester,year)
student(ID,name,dept_name,tot_cred)
takes(ID,course_id,sec_id,semester,year,grade)
advisor(s_ID,i_ID)
time_slot(time_slot_id,day,start_time,end_time)
prereq(course_id,prereq_id)
原文链接: 3.3.2 多关系查询