基本运算
每一种基本运算的结果都是一个新的关系,可以用这个关系继续参与运算,借此便可进行复杂的运算
选择运算(select)==>相当于SQL语句中的WHERE子句的职能
投影运算(project)==>相当于SQL语句中的SELECT子句的职能
关系的组合运算==>就像SQL中select、where子句那样的组合效果
举个栗子
∏ENAME,SAL(σSAL>1000(EMP))
上面的式子求出了所有工资大于1000的员工的名字和工资(实际上就是将σSAL>1000(EMP)执行的结果当做一个临时的关系,参与了投影运算得到的)
- 等价于下面的SQL语句
1
2
3SELECT ENAME, SAL
FROM EMP
WHERE SAL > 1000
事实关系的组合运算就是那么简单,分析的时候把每个简单运算的结果当做一个新的关系参与后面的运算,这样一层层剥开来,再复杂的语句也变得容易分析
并运算(union)==>相当于SQL中UNION关键字的职能
格式:(关系r)∪(关系s)
举个栗子
∏ENAME,SAL(σSAL>1000(EMP)) ∪ ∏ENAME,SAL(σCOMM>300(EMP))
上面的式子求出了所有工资大于1000或抽成大于300的员工的姓名和工资,等价于下面的SQL语句
1
2
3
4
5
6
7SELECT ENAME, SAL
FROM EMP
WHERE SAL > 1000
UNION
SELECT ENAME, SAL
FROM EMP
WHERE COMM > 300
几点需要额外注意的:
此处的并运算是集合运算,所以结果是去重的,结果集中不存在重复的元组(而在SQL语句中,指定UNION ALL是可以保留重复的)
关系r与关系s必须是同元的,即它们的属性的数目要求必须相同(这就和SQL语句中UNION使用的时候要求上下两个语句的字段数相同是一样的意思)
- 关系r和关系s对应位置的属性域应该是类型兼容的(同样和SQL中UNION使用时,每个对应位置字段类型兼容是一样的意思)
集合的差运算(set-defference)==>相当于SQL语句中的EXCEPT
笛卡尔积运算(Cartesian-product)==>等价于SQL语句中两个表进行笛卡尔积(全匹配)得到的结果,即SQL中进行多表连接时不指定连接条件的情况
格式:(关系r)×(关系)
举个栗子:
- EMP × DEPT
- 上面的式子表示两个表进行全匹配,等价于下面的SQL语句
1
2SELECT *
FROM EMP, DEPT
下面两个式子是等价的
- ∏ENAME,DNAME(σEMP.DEPTNO=DEPT.DEPTNO(σJOB=”MANAGER”(EMP×DEPT)))
- ∏ENAME,DNAME(σEMP.DEPTNO=DEPT.DEPTNO((σJOB=”MANAGER”(EMP))×DEPT)
- 下面是对这两个式子的SQL转化,转化之后就一目了然了
1
2
3
4
5
6
7
8
9
10
11-- 对应第一个式子
SELECT ENAME, DNAME
FROM EMP JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO
WHERE JOB = 'MANAGER'
-- 对应第二个式子
SELECT ENAME, DNAME
FROM DEPT JOIN (SELECT *
FROM EMP
WHERE JOB = 'MANAGER')
ON EMP.DEPTNO = DEPT.DEPTNO
更名运算(rename)==>等价于SQL语句中as的职能
来,学习完上面的基本运算,来做个实际的栗子,要求找到员工表中的最高工资(因为目前还没有介绍类似SQL中组函数的操作,后面会介绍。所以通过以下方式来实现)
- step1: 找到所有不是最高工资的人
- ∏e1.SAL(σe1.sal < e2.sal(ρe1(EMP)×ρe2(EMP)))
- step2: 用所有的员工减去上面的员工,即得到最高工资
- ∏SAL(EMP) - ∏e1.SAL(σe1.sal < e2.sal(ρe1(EMP)×ρe2(EMP)))
- step1: 找到所有不是最高工资的人
在书写关系运算表达式的时候可以用序列号代替字段名(但是不直观,不常用,一般不用)
- 举个栗子
- ∏$6(σ$6 < $14(EMP×EMP))
- 等价于下面的运算
- ∏e1.SAL(σe1.sal < e2.sal(ρe1(EMP)×ρe2(EMP)))
- 举个栗子
附加运算
附加运算是由基本运算组成的,不能增强基本运算的运算能力,但是能简化运算
集合交运算(intersection)==>相当于SQL语句中INTERSECT关键字的职能
自然连接(natural join)==> 相当于SQL语句中的NATURAL JOIN
格式:(关系)⋈(关系)
自然连接的形式化定义
- r,s是两个关系
- R,S是上面两个关系对应的关系模式(其实就是上述两个关系各自的属性列表)
- R ∩ S 表示r和s的同名属性列表
- R ∪ S 表示出现在r或s上的属性名列表(是一个集合,不包同名属性,存在同名属性会去重)
- R - S 表示出现在R上,但不出现在S上的属性名列表
- 则可做如下定义
- r⋈s = ∏R∪S(σr.A1=s.A1 ∧ r.A2=s.A2 ∧ … ∧ r.An=s.An(r×s)) ,其中 R∩S={A1, A2, …, An}
- 举个栗子
- ∏name, course_id(instructor ⋈ teaches)
- 上面的式子列出了所有老师的名字以及其所授课程的id,等价于下面的SQL语句
1
2SELECT name, course_id
FROM intructor natural join teaches
ps: 两个关系模式执行自然连接以后属性的排布顺序:
theta连接==>是带限定条件的笛卡尔积
格式:(关系)⋈Θ(关系)
- 形式化定义:
- r ⋈Θ s = σΘ(r × s)
- 举个栗子
- ∏name, course_id(instructor ⋈instructor.ID = teaches.ID ∧ instructor.salary > 5000 teaches)
- 上面的式子表示列出所有工资大于5000的老师的名字以及其所授课程的id, 等价于下面的SQL语句
1
2
3
4-- 使用 join...on 的时候 on 后面写连接条件,然后将其它条件放在where里
SELECT name, course_id
FROM instructor join teaches on instructor.ID = teaches.ID
WHERE instructor.salary > 5000
除运算(division)
这个在书上没讲,是老师上课的时候补充的
赋值运算
就是将一个关系表达式的结果赋值取一个临时的名字,就相当于定义了一个临时关系。这个操作就相当于SQL中with语句的职能
外连接运算
- 左外连:⟕
- 右外连:⟖
- 全外连:⟗
扩展运算
扩展运算是不能用基本的关系代数运算来实现的一类查询,可以满足复杂的查询需求
广义投影(Generalized-projection)
与基本运算中的投影运算相比,就是多了允许在选择列表中出现表达式(在基本运算中的投影的选择列表中只能出现字段)
聚集函数(Aggregation function)
聚集函数的符号表示是用书写体G,这边就直接用G指代了
聚集函数是输入值的一个汇聚,以多个值作为输入,将一个单一的值作为返回结果
多重集:使用聚集函数对其进行操作的汇集中,一个值可以出现多次,值出现的顺序是无关紧要的。这样的汇集称为多重集(就比方说统计一个员工表中员工的数量,然后我们通过统计员工的名字来统计,即便是同名的员工我们也是计算的)
格式: G1, G2, … , GnGF1(A1), F2(A2), …, Fn(An)(E)
- 其中前面的G1, G2, … , Gn表示的是分组条件
- 后面的F1(A1), F2(A2), …, Fn(An)是聚集函数表达式列表
- Fi(i = 1, 2, …, n)表示聚集函数:sum、count、average、max、min
- A1, A2, … , An代表字段
举个栗子:
- A1, A2Gsum(A3)(∏A1, A2, …, An(σP(r1×r2×…×rm)) )
- 等价于下面的SQL语句
1
2
3
4SELECT A1, A2, sum(A3)
FROM r1, r2, ..., rm
WHERE P
GROUP BY A1, A2
上面的聚集函数在进行计算的时候采用的都是多重集,也就是相同的值可以多次重复计算(也就是在执行聚集函数的时候是不去重计算),如果要去重计算的话就要采用下面的几个函数写法
- sum_distinct
- count_distinct
- averag_distinct
- max_distinct
- min_distinct
- 举个栗子:
- A1, A2Gsum_distinct(A3)(∏A1, A2, …, An(σP(r1×r2×…×rm)) )
- 上面的式子等价于下面的SQL语句
1
2
3
4SELECT A1, A2, sum(distinct A3)
FROM r1, r2, ..., rm
WHERE P
GROUP BY A1, A2