3.中级SQL
一些更复杂的查询表达
3.1 连接表达式
拼接多张表的几种方式
3.1.1 自然连接
natural join,自动连接在所有
共同属性上相同的元组
join… using( A 1 , A 2 , ⋯ A_1,A_2,\cdots A1,A2,⋯):使用括号里的属性进行自然连接,除了这些属性之外的共同属性不必相同
join…on… on后可以接任何SQL谓词,其实可以卸载where里
比如学生和所选课程的连接,他们都有共同的属性course_id和dept_name,如果直接使用natural join ,某些学生选择了不是自己院系的课,这种元组是有意义的,但会被排除,因此应该使用join takes using(course_id)
3.1.2 外连接
外连接通过在结果中创建包含空值的元组,来保留那些在连接中会丢失的元组。例如某些学生没有选课,那么
select *
from student join takes using (course_id)
将会丢失这些学生的信息,但如果使用
select *
from student left outer join takes on students.ID = takes.ID;
那些没有选课的学生的takes.ID将会被置为null,即不匹配会被置为空值
有三种形式的外连接:
- **左外连接(natural left outer join):**只保留左外连接运算之前(左边)的关系中的元组
- 右外连接(natural right outer join):只保留出现在右外连接运算之后(右边)的关系中的元组
- 全外连接(natural full outer join):保留出现在两个关系中的元组
不匹配的元组将会被补上空值,加入到连接结果中
例子:显示Comp.Sci 系中所有学生以及他们在2017年春季选修的所有课程段的列表,2017年春季开设的所有课程段都必须显示,即使没有来自Comp.Sci 系的学生选修这些课程段。
select *
from (select *
from student
where dept_name= 'Comp.Sci')
natural full outer join
(select *
from takes
where semester='Spring' and year = 2017);
由于学生可能没学课,课也可能没人选,两边都会出现空值,使用全外连接。
注意natural表明是自然的,即所有共同属性上,如果要使用on和using,不要加natural
3.2 视图
个人认为就是函数,但会将函数的结果保存起来。
3.2.1 视图定义
在SQL中通过使用create view命令来定义视图,且需要给视图一个名称,则格式为
c
r
e
a
t
e
v
i
e
w
v
a
s
<
查询表达式
>
;
create\ view\ v\ as\ <查询表达式>;
create view v as <查询表达式>;
例如,创建一个这样的视图:列出物理系在2017年秋季学期所开设的所有课程段,以及每个课程段在哪栋建筑的哪个房间授课:
create view physics_fall_2017 as
select course.course_id,sec_id,building,room_number
from course,section
where course.course_id = section.course_id
and course.dept_name='Physics'
and section.semester='Fall'
and section.year = 2017;
3.2.2 在SQL查询中使用视图
例如,使用视图physics_fall_2017,查询周到2017年秋季学期,在Watison大楼开设的所有物理课程:
select course_id
from physics_fall_2017
where building='Watson';
视图的属性名可以按下述方式来显示指定:
create view departments_total_salary(dept_name,total_salary) as
select dept_name,sum(salary)
from instructor
group by dept_name;
给sum(salary)显示指定了属性名为total_salary
在视图中也可使用另一个视图(函数嵌套)
create view physics_fall_2017_watson as
select course_id,room_number
from physics_fall_2017
where building='Watson';
3.2.3 物化视图
定义:某些数据库系统允许存储视图关系,但是他们保证:如果用于定义视图的实际关系发生改变,则视图也跟着修改以保持更新。这样的视图被称为物化视图(materialized view)
视图的运算结果也是一个表,例如department_total_salary中,如果instructor又插入了一个元组,那么原视图的查询结果也应该发生变化,即物化视图的内容也必须更新。
保持物化视图一直在最新状态的过程称为物化视图维护,或简称为视图维护。
3.2.4 视图更新
视图可更新的条件:
- from子句中只有一个数据库关系
- select子句中只包含关系的属性名,而不包含任何表达式,聚集或distinct 声明
- 没有出现在select子句中的任何属性都可以取null值;也就是说,这些属性没有非空约束,也不构成主码的一部分
- 查询中不含有group by或having子句
在这些限制下,允许在下面的视图上执行update、insert和delete操作
但即使满足上述条件,也会出现一些问题,例如插入的元组不满足视图的选择条件,则依然会被拒绝更新,但在缺省情况下,SQL允许执行上述更新。可以通过在视图定义的末尾包含with check option子句的方式来定义视图,这压根,如果向视图插入一条不满足视图的where子句条件的元组,则会拒绝插入。更新也是类似的
3.3 事务
事务(transaction)由查询和(或)更新语句的序列组成。SQL标准规定当一条SQL语句被执行时,就隐式地开始了一个事务:
- commit work 提交当前事务;则事务执行的更新在数据库中称为永久性的。在事务被提交后,一个新的事务会自动开始
- rollback work 回滚当前事务;撤销事务中SQL语句执行的所有更新。数据库状态被恢复到它执行该事务的第一条语句之前的状态。
关键字work在两个语句中都是可选的
一个事务或者在完成所有步骤后提交操作,或者不能成功完成其所有动作的情况下回滚其所有动作,通过这种方式数据库提供了对事务具有原子性(atomic)的抽象,要么事务的所有影响被反映到数据库中,要么任何影响也没有。
在缺省方式下每条SQL语句自成一个事务,且语句一旦执行完就提交该事务,如果一个事务由需要执行的多条SQL语句组成,就必须关闭单条SQL语句的这种自动提交。
MySQL支持begin语句,该语句启动包含所有后续SQL语句的事务,但不支持end语句;事务必须通过commit work或rollback work命令来结束
3.4 完整性约束
完整性约束保证授权用户对数据库所作的修改不会导致数据一致性的丢失。因此,完整性约束防止的是对数据的意外破坏。
通过创建关系的create table命令的一部分被声明。也可通过使用alter table table-name add constraint 命令将完整性约束施加到已有关系上。当这样一条命令被执行时,系统首先保证该关系满足指定的约束。如果满足,那么约束被施加到关系是;如果不满足,则上述命令被拒绝执行。
3.4.1 单个关系上的约束
允许的完整性约束包括:
- not null
- unique
- check(<谓词>)
示例
CREATE TABLE Persons
(
Id_P int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
PRIMARY KEY (Id_P) //PRIMARY KEY约束
)
3.4.2 非空约束
非空约束不允许为空值,按以下方式声明:
3.4.3 唯一性约束
SQL还支持这种完整性约束:
unique ( A j 1 , A j 2 , ⋯ , A j m ) (A_{j_1},A_{j_2},\cdots,A_{j_m}) (Aj1,Aj2,⋯,Ajm)
唯一性(unique)声明指出属性 A j 1 , A j 2 , ⋯ , A j m A_{j_1},A_{j_2},\cdots,A_{j_m} Aj1,Aj2,⋯,Ajm形成一个超码;意味着没有两个元组能在所有列出的属性上取值相同。然而声明了唯一性的属性允许为null,除非它们已被显示地声明为非空
3.4.4 check子句
当应用于关系声明时,check( P P P)子句指定一个谓词P,每个元组都要满足
例如:
create table section
(course_id varchar(8) not null,
sec_id varchar(8) not null,
semester varchar(6) not null,
year numeric(4,0) not null,
...
time_slot_id varchar(4),
primary key(course_id,sec_id,semester,year),
check(semester in('Fall','Winter','Spring','Summer'))
);
使用check子句模拟了一个枚举类型,通过指定semester必须是春夏秋冬中地一个。
此外,check子句的判断条件为不为假即满足,因此计算结果为未知的子句也是满足的,入股哦不需要空值,则必须指定单独的非空约束
3.4.5 引用完整性
保证一个关系(引用关系)中给定属性集合的取值也在另一个关系(被引用关系)的特定属性集的取值中出现,这种情况称为引用完整性约束。
通过使用外码(foreign key)子句,可以将外码指定为SQL的创建表语句的一部分。
例如 course表的定义中有一个声明foreign key (dept_name) references department ,表明:对于每个课程元组,元组中指定的系名必须在department关系中存在。如果没有这个约束,就可能会为一门课程指定一个并不存在的系名。
也可以指定为foreign key (dept_name) references department(dept_name),显示的声明。一般在缺省情况下,外码引用的时被引用表的主码属性,在显示指定下,这个被指定的属性列表必须声明为被引用关系的超码,要么使用主码约束,要么使用唯一性约束来进行这种声明。
外码必须引用一组兼容的属性,即属性数量必须相同,并且对应属性的数据类型必须兼容
级联删除(ondelete cascade):当违反引用完整性约束时,通常直接拒绝,但如果被引用关系上的删除或更新操作违反了约束,那么系统必须采取一些措施来改变引用关系中的元组以恢复完整性约束,而不是拒绝这样的操作。这个时候需要使用级联删除、级联更新。
create table course(
...
foreign key (dept_name) references department
on delete cascade
on update cascade,
...
);
如果删除department中的一个元组导致违反了这种引用完整性约束,系统不拒绝该删除,二是对course关系左“级联(cascade)”删除,级删除引用了被删除系得元组。更新也是同理。
也可用set null、set default来代替cascade,前者置为null,后者置为域得缺省值
3.4.6 给约束赋名
salary numeric(8,2),constraint minsalary check(salary>29000),
alter table instructor drop constaint minsalary;
3.4.7 事务中对完整性约束的违反
后续有点高深了,遇到了再说吧