本文只介绍一些基础中级SQL 对于其中各个语句涉及到的具体的底层原理,会在后续阅读书的后续章节更新
文章中的sql语句都是SQL标准规定的,具体到某些数据库中,可能会存在出入
文章的一些操作、实例都是在Mysql下执行的
自然连接运算作用于两个关系,并产生一个关系作为结果。自然连接只考虑在两个关系的模式中都出现的哪些属性上取值相同的元组。
r natural g
select attr_id,attr_name,attr_group_id
from pms_attr natural join pms_attr_attrgroup_relation;
可以指定一个属性名列表:
r1 join r2 using(A1,A2)
:要求 r1.A1 与 r2.A1,r1.A2 与 r2.A2 相同,即使r1、r2有相同的属性A3 也不需要相同。
假设在 r 表中的一个元组除了在 r 表中存在外,在 g 表中并不存在相同的属性。这种元组在自然连接时,会被排除掉。
而使用外连接,可以保留此元组,并将该元组 g 表中的属性设置为空。
三种形式的外连接,分别决定保留哪个关系的元组:
为了与外连接区分,将之前学习的不保留未匹配元组的连接运算称为内连接运算。
natural left/full/right outer join
on 连接条件在一般情况下与 where 用处相同,但是在与外连接相邻时,on 是外连接语句的一部分,但 where 子句 却不是。
在SQL 中把常规连接称为内连接
当join 子句中没有使用 outer 前缀时,缺省的连接类型是内连接。从而
select *
from student join takes using(ID);
等价于:
select *
from student inner join takes using(ID);
类似地,自然连接等价于自然内连接:
连接类型 | 连接条件 |
---|---|
inner join | natural |
left outer join | on |
right outer join | using (A1,A2,…,An) |
full outer join |
我们可以将查询的结果保存下来,保存为视图方便我们经常调用或者适用于不同权限的人员访问。
有点类似于我们之前学习的 with 子句,但是 with 子句只能在一个特定的查询中使用。
create view v as <查询表达式>
,查询表达式可以是任何合法的查询表达式。视图名称用v表示。
因为表达式 sum(salary) 并没有一个名称,所以在视图定义时指定了该属性名
create view departments_total_salary(dept_name,total_salary) as
select dept_name,sum(salary)
from instructor
group by dept_name;
**注意 :**为了避免一旦修改定义该视图的关系时视图就会过期。我们通常这样定义视图:数据库系统存储视图本身的定义,而不存储定义该视图的查询表达式的求值结果
可以看到视图的定义知识一条创建视图查询语句,所以当我们修改原来关系中的属性类型或属性值时,视图中相应的数据也会修改。因为在每次查询视图时都是在“重新创建视图”
顺理成章地,可以基于视图查询的结果创建视图
物化视图:某些数据库允许存储视图关系。如果用于定义视图的实际关系发送改变,则视图也跟着修改以保存最新。
如果该视图时物化的,数据库将其结果存储在数据库中,从而允许使用视图的查询可以通过使用预计算的视图结果来更快地运行,而不是重新计算视图的结果。
物化视图维护(视图维护):保持物化视图一直在最新状态的过程。
假设我们向视图中添加一个元组(A1,A2,…,An),但是A1属性不存在视图中,但存在于定义视图的关系中,那么是否能够插入成功?
由于上述情况的种种问题,除了一些有限的情况,并不允许对视图关系进行更新。
只有在满足以下条件时,才可以对视图进行更新:
定义视图的关系:
事务:由查询和(或)更新语句的序列组成。
SQL标准规定当一条SQL语句被执行时,就隐式开始了一个事务。下列语句之一会结束该事务:
如果在一个事务的执行期间检测到某种错误,事务回滚是有效的。在断电或其他系统崩溃时,回滚会在系统重启时执行。
一个事务或者在完成其所有步骤后提交其操作,或者在不能成功完成其所有动作的情况下回滚其所有动作,通过这种方式数据库提供了对事务具有原子性的抽象,原子性也就是不可分割性。要么事务的所有影响被反映到数据库中,要么任何影响也没有(在回滚之后)。
在大多数的数据库中的缺省模式下,每条SQL自成一个事务,且语句一旦执行完成就提交该事务。如果一个事务需要多条SQL语句组成,就必须关闭单条SQL语句的这种自动提交。很多数据库都提支持关闭自动提交的命令。
完整性约束:保证授权用户对数据库所做的修改不会导致数据一致性的丢失。
像我们之前学习的主码、外码、not null 都属于完整性约束
非空约束禁止对该属性插入空值。它是域约束的一个实例。
主码默认实现非空约束。
unique(A1,A2,...,An)
唯一性声明在关系中没有两个元组能在所有列出的属性上取值相同
唯一性的属性 允许为空(除非声明非空),因为空值不等于其他的任何值。
当应用于关系时,check§子句指定了一个谓词P,关系中的每个元组都必须满足谓词P。
create table student
(id varchar(8),
age varchar(8),
sex varchar(8),
check(age >= 18));
foreign key(dept_name) references department
这个语句声明:对于每个课程元组,元组中指定的系必须在 department 关系中存在。
有些系统(包括Mysql)并行指定引用关系的属性
还可以在外码子句中声明级联删除、级联更新。
foreign key(dept_name) references department
on delete cascade
on update cascade;
如果删除外码引用的关系中的一个元组违反了这种引用完整性约束,则系统并不拒绝该删除,而是对当前关系进行**“级联”**删除,即删除引用了被删除系的元组。
我们可以在约束的前面使用constraint + name 进行赋名
constraint minsalary check(salary > 20000)
也可以使用约束名删除约束:
alter table instructor drop constraint minsalary
事务中对完整性约束违反的例子:
SQL 标准允许将initally deferred 子句加入约束声明中;这样约束就不是在事务的中间步骤上检查,而是在事务结束的时候检查。
对于约束可以设置延迟执行,但在大多数数据库都不支持,所有不再介绍。
一个断言(assertion)就是一个谓词,它表达了我们希望数据库总能满足的一个条件。
create assertion credits_earned_constraint check
(not exists(select ID
from student
where tot_cred <> (select coalesce(sum(credits),0)
from takes natural join course
where student.ID = takes.ID
and grade is not null and grade<> 'F')));
SQL 标准支持与时间与日期相关的几种数据类型:
date ‘2020-9-15’
time ‘17:38:24’
timestamp ‘2020-9-15 17:38:24.45’
一些函数:year(date\timestamp)、month(date\timestamp)等等可以返回对应日期、时间的年月日等。
如果x和y都是 date 类型,那么 x-y 就是一个时间区间,其值为 x与y 间隔的日期
cast(e as t)
:将表达式 e 转换为 类型 t
select cast(ID as numeric(5)) as inst_id
from instructor
order by inst_id
SQL 允许为属性指定缺省值
create table student
(...
tot_cred numeric(3,0) default());
tot_cred 的默认值为0
SQL为字符数据(clob)和二进制数据(blob)提供了大对象数据类型。lob => large object
book_review clob(10kb)
image blob(10MB)
movle blob(2GB)
支持两种形式的自定义类型:独特类型、结构化数据类型。
在这里只介绍独特类型。
create type Dollars as numeric(12,2) final;
create table department
(dept_name varchar(20),
building varchar(15),
budget Dollars);
独特类型创建的属性具有强类型检查,因此表达式(department.budget + 20)将不会被接受。
其实早在SQL引入 自定义类型 之前,SQL 就有与自定义类型相近的概念:域(domain)。
create domain YearlySalary numeric(8,2)
constraint salary_value_test check(value >= 29000.00)
唯一码值会根据插入的元组自动递增,插入元组时不必设置唯一码值。
唯一码值一般都是主码,并且需要设置非空。
在Mysql 中,id bigint(20) auto_increment
来设置唯一码值。
create table r like t
创建一个和 t 表结构相同的 r 表。
create table r as (select * from t where name = 'Merist') with data
自定义从 t 表中获取到的属性与值创建一个 r 表。
with data
:是否创建时添加数据。
create table ... as
与 create view
非常相似,但是create view
的实质是一条查询语句,它的所有属性、数据都是动态获取的。
create table ... as
创建的是表,一旦建成,与原表没有任何关系。
在SQL 中,规定数据给的体系结构依次按照包含关系由 目录、模式组成
在Mysql 中,“数据库”对应“目录”,“表、视图”对应模式。
关系属性上的索引是一种数据结构,它允许数据库高效地找到在关系中具有该属性指定值的那些元组,而不扫描关系的所有元组。
create index <索引名> on <关系名>(<属性列表>)
SQL查询处理器将使用定义的索引来查询所需的元组,而不是读取整个关系。
drop index <索引名>
删除索引
对数据的授权:
SQL 标准包括 选择(select)、插入(insert)、更新(update)、删除(delete)权限。
授权语句:
grant <权限列表>
on <关系名或视图名>
to <用户或角色列表>
收权语句:
revoke <权限列表>
on <关系名或视图名>
to <用户或角色列表>
在SQL标准中,规定了一个角色集来存放用户及其权限的数据。其中的每个用户就叫做角色。
在Mysql中,数据库所有用户权限信息默认存储在数据库mysql 中的 user 表中。可以使用查询语句查询用户的权限。
grant select on r to username with grant option
一个用户具有权限的充要条件是:当且仅当存在从授权图的根(即代表数据库管理员的节点)到代表该用户的节点的路径。
为了防止用户通过互相授权来破坏权限的收回规则,在默认情况下,数据库的收回都遵守级联收回。
级联收回:从一个用户、角色那里收回权限可能导致其他用户、角色也失去该权限。
授权也可以声明限定(restrict)来防止级联收回:
revoke select on department from Amit,Satoshi restrict
关键字cascade
可以替代restrict
来使用级联回收,不过一般省略。
我们已经学习过的授权类型适用于关系或视图级别。一些数据库系统在关系中的特定元组级别提供了细粒度的授权机制。
例如,假设我们希望允许学生在takes关系中查看他自己的数据,但不允许查看其他用户的那些数据。如果数据库支持,我们可以使用行级授权来强制实施此类限制。下面我们将描述 Oracle 中的行级授权;PostgreSQL 和 SQL Server 也使用概念上类似的机制来支持行级授权,但使用的是不同的语法。
Oracle 虚拟私有数据库( Virtual Private Database , VPD )功能支持如下所示的行级授权。它允许系统管理员将函数与关系相关联;该函数返回一个谓词,该谓词会自动添加到使用该关系的任何查询中。该谓词可以使用sys_context函数,它返回代表正在执行查询的用户的标识。对于我们的示例,学生需要访问他们在takes关系中的数据,我们将指定以下谓词与takes关系相关联:
ID=sys_context('USERENV','SESSIONUSER')
系统将此谓词添加到使用takes关系的每个査询的where子句中。其结果是,每名学生只能看到ID值与其ID 相匹配的那些takes元组。
VPD提供了关系的特定元组或行的级别上的授权,因此被称为行级授权( row - level authorization )机制。如上所述添加谓词的一个隐患是:它可能会显著改变查询的含义,例如,如果一个用户编写查询来查找所有课程的平均成绩,则他最终会得到他的成绩的平均值,而不是所有成绩的平均值。虽然系统会为重写的查询提供“正确”的答案,但用户可能认为该答案与其所提交的查询不对应。