数据库系统概论——SQL

一、SQL查询语言概览

miVqVU.png
视图

  • 从一个或几个基本表导出的表
  • 数据库中只存放视图的定义而不存放视图对应的数据
  • 视图是一个虚表
  • 用户可以在视图上再定义视图

基本表

  • 本身独立存在的表
  • SQL中一个关系对应一个基本表
  • 一个(或多个)基本表对应一个存储文件
  • 一个表可以带若干索引

存储文件

  • 逻辑结构组成了关系数据库的内模式
  • 物理结构对用户是隐蔽的

二、数据定义

miZCqK.png

2.1数据类型

定义表的属性时需要指明其数据类型及长度
miZVGd.png

2.2模式

  • 一个数据库中可以建立多个模式
  • 一个模式下通常包括多个表、视图和索引等数据库对象
  • 每一个基本表都属于某一个模式

2.2.1定义模式

定义模式实际上定义了一个命名空间,在这个空间中可以定义该模式包含的数据库对象,例如基本表、视图、索引等

create schema <模式名> [<模式元素>...]
/*
创建一个以<模式名>命名的模式,并可以在创建模式的同时为该模式创建或不创建模式元素
模式元素可以是表定义、视图定义、断言定义、授权定义等
该格式可在以后用授权语句向其他用户授权访问创建的模式
*/

--或
create schema [<模式名>] authorization <用户名> [<模式元素>...]
--将创建的模式授权于<用户名>指定的用户。当<模式名>缺省时,用<用户名>作为模式名

例:为用户 Zhang创建了一个模式 test,并且在其中定义一个表 tab1

create schema test authorization Zhang;

create table tab1 (
    col1 smallint,
    col2 int,
    col3 char(20),
    col4 numeric(10,3),
    col5 decimal(5,2)
    );

2.2.2删除模式

drop schema <模式名> cascade|restrict

cascade(级联)
--删除模式的同时把该模式中所有的数据库对象全部删除
restrict(限制)
--如果该模式中定义了下属的数据库对象(如表、视图等),则拒绝该删除语句的执行

删除上例中建立的模式

drop schema zhang cascade;
--删除模式 Zhang,同时该模式中定义的表 tab1也被删除

2.3基本表

2.3.1定义基本表

create table <表名> (
    <列名> <数据类型> [default <缺省值>] [列级约束定义],
    <列名> <数据类型> [default <缺省值>] [列级约束定义],
    ...,
    [<表级约束定义>, ..., <表级约束定义>]
    );

--表名:基本表的名字
--列名:组成表的各个属性

--列级约束定义
    [constraint <约束名>] <列约束>
    --常用的列约束:
    --not null:不允许该列取空值
    --primary key:指明该列是主码,非空、唯一
    --unique:该列上的值必须唯一,即该列为候选码
    --check (<条件>):指明该列的值必须满足的条件,<条件>是一个涉及该列的布尔表达式

--表级约束定义
    [constraint <约束名>] <列约束>
    --常用的表约束:
    --primary key (A1, ..., Ak):属性列 A1, ..., Ak构成该关系的主码。当主码只包括一个属性时,也可以用列级约束定义主码
    --unique (A1, ..., Ak):属性列 A1, ..., Ak上的值必须唯一,即 A1, ..., Ak构成候选码。当候选码只包括一个属性时,也可以用列级约束定义主码
    --check (<条件>):说明该表上的一个完整性约束条件,<条件>是一个涉及该表一个或多个列的布尔表达式
    --foreign key (A1, ..., Ak) references <外表名> (<外表主码>) [<参照触发动作>]:属性 A1, ..., Ak是关系(表)的外码,<外表名>给出被参照关系的表名,<外表主码>给出被参照关系的主码,<参照触发动作>说明违反参照完整性时需要采取的措施

--如果完整性约束条件涉及到该表的多个属性列,则必须定义在表级上,否则既可以定义在列级也可以定义在表级

例:建立一个“课程”表Course

create table Course (
    Cno char(4) primary key, --Cno是该表的主码
    Cname char(40),
    Cpno char(4),
    Ccredit smallint,
    --primary key(Cname,Cpno), "Cname,Cpno共同构成了该表的主码"
    foreign key (cpno) references course(cno)
    );

2.3.2修改基本表

alter table <表名>
    [ add [column] <列名> <数据类型> [列级约束定义] ]
    [ alter [column] <列名> {set default <缺省值>|drop default} ]
    [ drop [ column ] <列名> {cascade|restrict} ]
    [ add <表级约束定义>]
    [ drop constraint <约束名> [cascade|restrict] ]

--add:增加新列、新的列级约束定义和表级约束定义
--drop column:删除表中的列
--cascade:自动删除引用了该列的其他对象
--restrict:如果该列被其他对象引用,关系数据库管理系统将拒绝删除该列
--drop constraint:删除指定的完整性约束条件
--alter column:修改原有的列定义,包括修改列名和数据类型

2.3.3删除基本表

drop table <表名> [restrict|cascade]
--删除基本表导致存放在表中的数据和表定义都将被彻底删除

2.4索引

建立索引的目的:加快查询速度

2.4.1建立索引

--索引可以建立在该表的一列或多列上,各列名之间用逗号分隔
create [unique] [cluster] index <索引名> 
    on <表名> ( <列名> [<次序>], ..., <列名> [<次序>] )

--表名:要建索引的基本表的名字
--次序:指定索引值的排列次序,升序:ASC,降序:DESC。缺省值:ASC
--unique:此索引的每一个索引值只对应唯一的数据记录
--cluster:表示要建立的索引是聚簇索引

例:为学生-课程数据库中的Student,Course,SC三个表建立索引。Student表按学号升序建唯一索引,Course表按课程号升序建唯一索引,SC表按学号升序和课程号降序建唯一索引

create unique index Student on student(sno);
create unique index Course on course(cno);
create unique index SC on sc(sno asc, cno desc);

2.4.2删除索引

drop index <索引名>
--删除索引时,系统会删除索引结构,并从数据字典中删去该索引的定义
数据查询
select [ all|distinct ] <选择序列>
from <表引用>, ..., <表引用>
[ where <查询条件> ]
[ group by <分组列>, ..., <分组列> [ having <分组选择条件> ] ]
[ order by <排序列> [ ASC|DESC ], ..., order by <排序列> [ ASC|DESC ] ]

--select子句:指定要显示的属性列
--from子句:指定查询对象(基本表或视图)
--where子句:指定查询条件
--group by子句:对查询结果按指定列的值分组,该属性列值相等的元组为一个组。通常会在每组中作用聚集函数
--having短语:只有满足指定条件的组才予以输出
--order by子句:对查询结果表按指定列值的升序或降序排序

一个SQL查询的含义

  1. 为 from子句中列出的关系产生笛卡尔积
  2. 在步骤1的结果上应用 where子句中指定的谓词
  3. 对于步骤2结果中的每个元组,输出 select子句中指定的属性或表达式的结果

三、单表查询

查询的输入是 from子句中列出的关系,在这些关系上进行 where和 select子句中指定的运算,最终产生一个关系作为结果

3.1选择表中的若干列

3.1.1查询指定列

--找出所有教师所在系的系名
select dept_name
from instructor;

3.1.2查询全部列

在 select关键字后面列出所有列名,或 将 <目标列表达式> 指定为 * ,表示“所有属性”

--选中 instructor中的所有属性
select instructor.*
from instructor,teacher
where instructor.ID = teacher.ID;

--select * 表示 from子句结果关系的所有属性都被选中,即 instructor,teaches的所有属性都被选中

3.1.3查询经过计算的值

select子句的 <目标列表达式> 可以是关系的属性,也可以是表达式 但不会导致对关系的任何改变

select salary-5000
from instructor;

3.1.4使用列别名改变查询结果的列标题

select Sname aName, 'Year of Birth:' Birth, 2014-Sage Birthday, lower(Sdept) Department
from Student;
--aName,Birth,Birthday,Department是别名

3.1.5更名运算

  • from子句中的多个关系中可能存在同名的属性,导致结果中出现重复的属性名
  • 如果在 select子句中使用算术表达式,结果属性就没有名字
  • 想改变结果中的属性名字

as子句既可以出现在 select子句中,也可以出现在 from子句中

--对于大学中所有讲授课程的教师,找出他们的姓名以及所讲述的所有课程标识
select T.name, S.course_id
from instructor as T, teaches as S
where T.ID = S.ID;

--使用 as语句重命名结果关系中的属性:old_name as new_name

3.2选择表中的若干元组

3.2.1消除取值重复的行

SQL允许在关系以及SQL表达式结果中出现重复,如果想强行删除重复,可在 select后加入关键词 distinct,缺省为 all

select Sno
from sc;
--等价于
select all Sno
from sc;

--指定关键词 distinct后消除重复行
select distinct dept_name
from instructor;

3.2.2查询满足条件的元组

miSrwR.png

select name
from instructor
where dept_name='Comp.Sci' and salary>70000;

3.3 ORDER BY子句

可以按一个或多个属性列排序
升序:ASC;降序:DESC;缺省值为 ASC
例:查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列

select Sno, Grade
from SC
where Cno='3'
order by Grade DESC;

3.4聚集函数

  • 统计元组个数 count( * )
  • 统计一列中值的个数 count([distinct | all] <列名> )
  • 计算一列值的总和(此列必须为数值型)sum([distinct | all] <列名> )
  • 计算一列值的平均值(此列必须为数值型)avg([distinct | all] <列名> )
  • 求一列中的最大值和最小值 max([distinct | all] <列名> ),min([distinct | all] <列名> )

sum和 avg的输入必须是数字集,其他运算符可作用在非数字数据类型的集合如字符串

3.5 GROUP BY子句

group by子句中给出的一个或多个属性用于构造分组,group by子句中的所有属性上取值相同的元组将被分在同一组

--找出每个系的平均工资
select dept_name, avg(salary) as avg_salary
from instructor
group by dept_name;

分组情况:
miSbff.png
最终结果:
mipl9K.png
任何没有出现在 group by子句中的属性如果出现在 select子句中,只能出现在聚集函数内部,否则该查询错误
having短语与 where子句的区别

  • 作用对象不同
  • where 子句作用于基表或视图,从中选择满足条件的元组
  • having 短语作用于组,从中选择满足条件的组

四、多表查询

同时涉及两个及以上的表的查询

4.1等值连接与自然连接

等值连接:关系R、S,取两者笛卡尔积中属性值相等的元组,例如 R.A=S.B,R.B=S.B
自然连接:特殊的等值连接。运算作用于两个关系并产生一个关系作为结果,在相同属性上进行相等比较,并投影去掉重复属性

列出属性的顺序:先是两个关系模式中的共同属性,然后是只出现在第一个关系模式中的属性,最后是只出现在第二个关系模式中的属性

--from子句中可以用自然连接将多个关系结合在一起
select A1, A2, … ,An
from R1 natural join R2 natural join … natural join Rm
where P;

4.2自身连接

自身连接:一个表与其自己进行连接
由于所有属性名都是同名属性,因此属性前必须给表起别名以示区别
例:查询每一门课的间接先修课(即先修课的先修课)

select first.Cno, second.Cpno
from Course first, Course second
where first.Cpno = second.Cno;

miprjg.png
mip43T.png

五、嵌套查询

5.1概述

一个 select-from-where语句称为一个查询块。将一个查询块嵌套在另一个查询块的 where子句或 having短语的条件中的查询称为嵌套查询

select Sname  /*外层查询/父查询*/
from Student
where Sno in (
            select Sno  /*内层查询/子查询*/
            from SC
            where Cno= '2'
            );
  • 上层的查询块称为外层查询或父查询
  • 下层查询块称为内层查询或子查询
  • SQL语言允许多层嵌套查询,即一个子查询中还可以嵌套其他子查询
  • 子查询的限制:不能使用ORDER BY子句

相关子查询:子查询的查询条件依赖于父查询

  1. 首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若 where子句返回值为真,则取此元组放入结果表
  2. 然后再取外层表的下一个元组
  3. 重复这一过程,直至外层表全部检查完为止

5.2带有 in谓词的子查询

谓词 in测试元组是否是集合中的成员,集合由 select子句产生的一组值构成

--找出在2009年秋季和2010年春季学期同时开课的所有课程
select distincy course_id
from section
where semester = 'Fall' and year = 2009 and course_id in (
                                                        select course_id
                                                        from section
                                                        where semester = 'Spring' and year = 2010
                                                        );

in和 not in操作符能用于枚举集合

--找出"Mozart"和"Einstein"之外的老师
select distincy name
from instructor
where name not in ('Mozart','Einstein');

5.3带有比较运算符的子查询

当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >)
“至少比某一个大”用 > some表示

--找出至少比 Biology系某一个教师的工资高的所有老师的姓名
select distinct T.name
from instructor as T, instructor as S
where T.salary > S.salary and S.dept_name = 'Biology';
--注意这里 as语句的用法

select name
from instructor
where salary > some (
                    select salary
                    from instructor
                    where depr_name = 'Biology'
                    );

“比所有的都大”用 > all表示

--找出比 Biology系所有教师的工资都高的所有老师的姓名
select name
from instructor
where salary > all (
                    select salary
                    from instructor
                    where depr_name = 'Biology'
                    );

5.4带有 exists谓词的子查询

带有 exists谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”

  • 若内层查询结果非空,则外层的where子句返回真值
  • 若内层查询结果为空,则外层的where子句返回假值

由exists引出的子查询,其目标列表达式通常都用 * ,因为带exists的子查询只返回真值或假值,给出列名无实际意义

六、集合查询

intersect, union, except分别对应交、并、差运算,均可以自动去除重复,若想保留重复只需在后面加上 "all"

6.1交运算

--找出2009年秋季和2010年春季同时开课的所有课程
(
select course_id
from section
where semester = 'Fall' and year = 2009
)
intersect
(
select course_id
from section
where semester = 'Spring' and year = 2010
);

--结果中出现的重复元组数等于在 c1和 c2中出现的重复次数里最少的那个

6.2并运算

--找出2009年秋季开课,或2010年春季开课,或两个学期都开课的所有课程
(
select course_id
from section
where semester = 'Fall' and year = 2009
)
union
(
select course_id
from section
where semester = 'Spring' and year = 2010
);

--结果中出现的重复元组数等于在 c1和 c2中出现的重复元组数的和

6.3差运算

--找出2009年秋季开课但不在2010年春季开课的所有课程
(
select course_id
from section
where semester = 'Fall' and year = 2009
)
except
(
select course_id
from section
where semester = 'Spring' and year = 2010
);
--except运算从其第一个输入中输出所有不出现在第二个输入中的元组

--结果中出现的重复元组数等于在 c1中出现的重复元组数减去 c2中出现的重复元组数(前提是结果为正)

七、基于派生表的查询

子查询不仅可以出现在 where子句中,还可以出现在 from子句中,这时子查询生成的临时派生表成为主查询的查询对象
如果子查询中没有聚集函数,派生表可以不指定属性列,子查询 select子句后面的列名为其缺省属性

--找出系平均工资超过50000美元的那些系中教师的平均工资
select dept_name,avg_salary
from (
    select dept_name,avg(salary)
    from instructor
    group by dept_name
    )
as dept_avg (dept_name,avg_salary) --括号外是表名,括号内是属性名
where avg_salary > 50000;
--子查询的结果关系被命名为 dept_name,其属性名是 dept_name和 avg_salary

八、数据更新

数据更新包括插入,删除,修改

8.1插入

8.1.1插入元组

insert into T [(A1, ..., Ak)]
    values (C1, ..., Ck)

/*
T是基本表
A1, ..., Ak是 T的属性
    into子句中属性的顺序可与表中定义的不一致:
        没有指定属性列:表示插入的是一条完整的元组,且属性与表定义中的顺序一致
        指定部分属性列:插入的元组在其余属性列上取空值
C1, ..., Ck是 A1, ..., Ak对应的取值
    values子句中提供的值必须与 into子句匹配
*/

例:插入 Computer Science系开设的名为"Database Systems"的课程 CS-437,4个学分

insert into course
    values ('CS-437', 'Database Systems', 'Comp. Sci.', 4);

--若用户不记得属性顺序,可以在 insert语句中指定属性
--上式等价于
insert into course (title, course_id, credits, dept_name)
    values ('Database Systems', 'CS-437', 4, 'Comp. Sci.');

8.1.2插入子查询结果

insert into T [(A1, ..., Ak)]
    <查询表达式>

/*
T是基本表或者视图
A1, ..., Ak是 T的属性
<查询表达式>是一个 select语句,其目标列必须与 into子句匹配
*/

例:对每一个系,求学生的平均年龄,并把结果存入数据库

--第一步:建表
create table Dept_age(
    Sdept char(15),  /*系名*/
    Avg_age smallint  /*学生平均年龄*/
    );

--第二步:插入数据
insert into Dept_age(Sdept, Avg_age) (
    select Sdept, Avg(Sage)
    from Student
    group by Sdept
    );

8.2修改

update T
    set A1 = C1, ..., Ak = Ck
    [where <修改条件>]

--T是基本表或视图
--A1, ..., Ak是 T的属性
--C1, ..., Ck是表达式

功能

  • 修改指定表中满足 where子句条件的元组
  • set子句给出的表达式的值用于取代相应的属性的值
  • 如果省略 where子句,表示要修改表中的所有元组

例:对工资低于平均数的教师涨5%的工资

update instructor
    set salary = salary*1.05
    where salary < (
                    select avg(salary)
                    from instructor
                    );
--SQL还提供 case结构进行多选择操作
case
    when pred1 then result1
    when pred2 then result2
    …
    when predn then resultn
    else result0
end


--给工资低于10000美元的教师涨5%的工资,其余涨3%
update instructor
    set salary = case
                    when case <= 10000 then salary*1.05
                    else salary*1.03
                 end

8.3删除

delete from T
    [where <删除条件>]

--T是基本表或视图

功能:删除指定表中满足WHERE子句条件的元组
where子句

  • 指定要删除的元组
  • 缺省表示要删除表中的全部元组,表的定义仍在字典中

delete命令只能作用于一个关系,但是可以通过在 where子句中嵌套子查询引用任意数目的关系
执行任何删除之前先对所有元组进行测试,测试完成后再进行删除操作,防止部分元组提前改变导致标准变动,引起结果错误
例:删除所有在位于 Waston大楼的系工作的教师元组

delete from instructor
where dept_name in (
                    select dept_name
                    from department
                    where building = 'Waston'
                    );

九、视图

特点

  • 虚表,是从一个或几个基本表(或视图)导出的表
  • 只存放视图的定义,不存放视图对应的数据
  • 基表中的数据发生变化,从视图中查询出的数据也随之改变

9.1定义视图

9.1.1建立视图

create view <视图名> [ (<列名>, ..., <列名>]) ]
    as <查询表达式>
    [with check option]

--with check option表示该视图是可更新的,且对视图更新时要满足<查询表达式>的查询条件
--create view是说明语句,它创建一个视图并将视图的定义存放在数据字典中,而定义中的<查询表达式>并不立即执行

组成视图的属性列名:全部省略或全部指定

  • 全部省略
  1. 由子查询中SELECT目标列中的诸字段组成
  • 明确指定视图的所有列名
  1. 某个目标列是聚集函数或列表达式
  2. 多表连接时选出了几个同名列作为视图的字段
  3. 需要在视图中为某个列启用新的更合适的名字

例:建立信息系学生的视图,并要求进行修改和插入操作时仍需保证该视图只有信息系的学生

--create view IS_Student
as 
    select Sno,Sname,Sage
    from Student
    where Sdept= 'is'
    with check option; --对该视图进行插入、修改和删除操作时,RDBMS会自动加上 Sdept='is'的条件

若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码,我们称这类视图为行列子集视图,上述 IS_Student视图就是一个行列子集视图。行列子集视图是可更新的

9.1.2删除视图

drop view <视图名> [cascade|restrict]

--从数据字典中删除指定的视图定义
--如果该视图上还导出了其他视图,使用cascade级联删除语句会把该视图和由它导出的所有视图一起删除
--删除基表时,由该基表导出的所有视图定义都必须显式地使用drop view语句删除

9.2查询视图

用户角度:查询视图与查询基本表相同
关系数据库管理系统实现视图查询的方法:视图消解法

  1. 进行有效性检查
  2. 转换成等价的对基本表的查询
  3. 执行修正后的查询

例:在信息系学生的视图中找出年龄小于20岁的学生

select Sno,Sage
from IS_Student
where Sage<20;

--视图消解转换后的查询语句为:
select Sno,Sage       
from Student
where Sdept= 'IS' and Sage<20;

有些情况下,视图消解法不能生成正确的查询
例:在S_G视图中查询平均成绩在90分以上的学生学号和平均成绩

select *
from S_G
where Gavg>=90;

--S_G视图的子查询定义: 
create view S_G (Sno,Gavg)
as
    select Sno,AVG(Grade)
    from SC
    --这里不能用 where AVG(Grade)>=90 !!!
    group by Sno
    having AVG(Grade)>=90;

9.3更新视图

视图的更新指通过试图进行增、删、改操作
由于视图都是直接或间接基于基本表定义的,因此基于视图的更新最终要转换成基于基本表的个更新
有些视图可以将更新唯一地转换成对定义它的基本表的更新,成为可更新的视图;有些视图不能将更新唯一地转换成对定义它的基本表的更新,成为不可更新的视图

--将信息系学生视图IS_Student中学号”201215122”的学生姓名改为”刘辰”
update IS_Student
set Sname= '刘辰'
where Sno= '201215122';

--转换后的语句:
update Student
set Sname= '刘辰'
where Sno= '201215122' and Sdept= 'IS';

/*插入,删除同理*/

允许对行列子集视图进行更新。对其他类型视图的更新不同系统有不同限制

9.4视图的作用

1、使一些查询表达更加简洁
2、提供了一定程度的逻辑独立性
3、起到安全保护作用
4、使用户能够以不同角度看待相同的数据

猜你喜欢

转载自www.cnblogs.com/xxwang1018/p/11546726.html