Ayy2

时间停止吧,你是多么的美丽

数据库安全性

挖坑


作业(

有以下两个关系模式:

职工(职工号,姓名,年龄,职务,工资,部门号)

部门(部门号,名称,经理名,地址,电话号)

请用SQL的GRANT语句和REVOKE语句(加上视图机制)实现以下授权定义或存取控制功能:

首先建表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
drop table 职工;
drop table 部门;

create table 职工(
职工号 VARCHAR(10) PRIMARY KEY,
姓名 VARCHAR(10),
年龄 SMALLINT,
职务 VARCHAR(12),
工资 NUMERIC(8, 2),
部门号 VARCHAR(10)
);
create table 部门(
部门号 VARCHAR(10) PRIMARY KEY,
名称 VARCHAR(16),
经理名 VARCHAR(10),
地址 VARCHAR(50),
电话号 VARCHAR(11)
);
insert into 职工 values('001', '王明', 35, '总经理', 8500, 'BM001');
insert into 职工 values('002', '李勇', 29, '架构师', 6200, 'BM002');
insert into 职工 values('003', '刘星', 30, '程序员', 5450, 'BM003');
insert into 职工 values('004', '张新', 32, '程序员', 5850, 'BM003');
insert into 职工 values('005', '周平', 30, '管理员', 6100, 'BM001');
insert into 职工 values('006', '杨兰', 24, '设计师', 4900, 'BM002');

insert into 部门 values('BM001', '部门一', '经理一', '地址一', '001');
insert into 部门 values('BM002', '部门二', '经理三', '地址二', '002');
insert into 部门 values('BM003', '部门三', '经理三', '地址三', '003');

创建用户:

1
2
3
4
5
6
7
8
9
10
create user c##wangming identified by 114514;
create user c##liyong identified by 114514;
create user c##liuxing identified by 114514;
create user c##zhangxin identified by 114514;
create user c##zhoupin identified by 114514;
create user c##yanglan identified by 114514;

grant connect, resource to c##wangming, c##liyong;
grant connect, resource to c##liuxing, c##zhangxin;
grant connect, resource to c##zhoupin, c##yanglan;

(1)用户王明对两个表有select权限。

1
2
grant select on 职工 to c##wangming;
grant select on 部门 to c##wangming;

(2)用户李勇对两个表有insert和delete权限。

1
2
grant insert, delete on 职工 to c##liyong;
grant insert, delete on 部门 to c##liyong;

(3)每个职工只对自己的记录有select权限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
create view view_wangming as select * from 职工 where 姓名 = '王明';
grant select on view_wangming to c##wangming;

create view view_liyong as select * from 职工 where 姓名 = '李勇';
grant select on view_liyong to c##liyong;

create view view_liuxing as select * from 职工 where 姓名 = '刘星';
grant select on view_liuxing to c##liuxing;

create view view_zhangxin as select * from 职工 where 姓名 = '张新';
grant select on view_zhangxin to c##zhangxin;

create view view_zhoupin as select * from 职工 where 姓名 = '周平';
grant select on view_zhoupin to c##zhoupin;

create view view_yanglan as select * from 职工 where 姓名 = '杨兰';
grant select on view_yanglan to c##yanglan;

(4)用户刘星对职工表有select权限,对工资字段有更新权限。

1
2
grant select on 职工 to c##liuxing;
grant update(工资) on 职工 to c##liuxing;

(5)用户张新具有修改这两个表的结构的权限。

1
2
grant alter on 职工 to c##zhangxin;
grant alter on 部门 to c##zhangxin;

(6)用户周平具有对两个表的所有权限,并具有给其他用户授权的权限。

1
2
grant all privileges on 职工 to c##zhoupin with grant option;
grant all privileges on 部门 to c##zhoupin with grant option;

(7)用户杨兰具有从每个部门职工中select最高、最低、平均工资的权限,但不能查看每个人的工资:

1
2
3
4
5
6
create view emp_sal as
select 部门号, max(工资) "最高工资", min(工资) "最低工资", avg(工资) "平均工资"
from 职工
group by 部门号;

grant select on emp_val to c##yanglan;

计网——应用层复习

应用层是计算机网络体系结构的最顶层,是设计和建立计算机网络的最终目的。

客户/服务器方式(C/S方式)和对等方式(P2P方式)

网络应用程序运行在处于网络边缘的不同的端系统上,通过彼此的通信来共同完成某些任务。

开发一种新的网络应用首先要考虑的问题就是网络应用程序在各种端系统上的组织方式和它们之间的关系

客户/服务器方式

对等方式

动态主机配置协议DHCP

  • 互联网广泛使用的DHCP提供了即插即用联网机制
  • 这种机制允许一台计算机加入新的网络和获取IP地址,而不用手工配置

DHCP工作过程

DHCP使用客户-服务器方式

  • 需要IP地址的主机在启动时就向DHCP服务器广播发送发现报文(DHCP DISCOVER),这时该主机就成为DHCP客户。
  • 本地网络上所有主机都能收到此广播报文,但只有DHCP服务器才回答此广播报文
  • DHCP服务器先在其数据库查找该计算机的配置信息。若找到,则返回找到的信息。否则从服务器的IP地址池(address pool)中取一个地址给该计算机。DHCP服务器的回答报文叫做提供报文(DHCP OFFER)

DHCP工作方式

  • DHCP使用客户-服务器方式,采用请求/应答方式工作。
  • DHCP基于UDP工作(因为TCP不支持广播???),服务器运行在67号端口,DHCP客户运行在68号端口。

DHCP交互过程

首先,DHCP客户广播发送DHCP发现报文,包含

  • 事务ID
  • DHCP客户端的MAC地址

封装该报文的IP数据报的IP地址位0.0.0.0,目的地址为广播地址255.255.255.255

DHCP服务器收到DHCP发现报文后,根据其中封装的DHCP客户端的MAC地址来查找自己的数据库,如果查到匹配信息,则使用这些配置信息来构建并发送DHCP提供报文,如果没有则采用默认配置信息来构建报文并发送。

DHCP服务端将广播发送DHCP提供报文(DHCP OFFER)

  • 事务ID:DHCP客户端会与之前DHCP发送报文的事务ID进行对比,来判断该DHCP报文是否是自己的
  • 源IP地址:服务器的IP 目的IP地址:广播地址

这里DHCP客户可能会收到不止一个DHCP提供报文,会从中选择一个,一般选择先到的,并向所选择的DHCP服务器发送DHCP请求报文。

源地址:0.0.0.0,因为此时DHCP客户需要征求服务器同意,才可使用获得的IP

目的地址:广播地址,这样可以一次性通知所有DHCP服务器,告知它们是否把它们作为自己的DHCP服务器

所选择的DHCP服务器接收该请求,向DHCP客户发送DHCP确认报文

DHCP客户收到该报文后,就可以使用租用的IP地址。在使用前还会进行ARP检测。

DHCP中继代理

idea:给路由器配置DHCP服务器的IP地址,使之成为中继代理,这样就不用在每一个网络上都设置DHCP服务器。

总结

域名系统DNS

DNS是一个分布式系统,使大多数域名都能在本地解析。

因特网采用层次树状结构的域名结构。域名的结构由若干的分量构成,各分量之间用“点”隔开,分别代表不同级别的域名:

可以看见,名称相同的域名,其等级未必相同。

DNS使用分布在各地的域名服务器来实现域名到IP地址的转换。

域名服务器可以划分为以下4个不同的类型:

域名解析分为递归查询和迭代查询。

DNS报文使用运输层的UDP协议进行封装,运输层端口号53.

文件传送协议FTP

  • FTP是因特网上使用得最广泛的文件传送协议
    • FTP提供交互式的访问,允许客户指明文件的类型和格式,并允许文件具有存取权限
    • FTP屏蔽各计算机系统的细节,因而适合于在异构网络中任意计算机之间传送文件

FTP采用C/S方式

FTP客户计算机可将各种类型的文件上传到FTP服务器计算机,也可以从FTP服务器计算机下载文件。

FTP基本工作原理

FTP服务器监听熟知端口(端口号21),使客户进程能够连接上。

FTP客户随机选择一个临时端口号与其建立TCP连接,这条TCP连接用于FTP客户和服务器之间传送FTP相关控制命令

FTP服务器使用自己的熟知端口号20与客户建立TCP连接,用于传送文件

这是主动模式:建立数据通道时,FTP服务器主动连接客户。

对比,被动模式的端口号由协商决定

电子邮件

邮件发送和接收过程

简单邮件传送协议(SMTP)

可以发现,非常麻烦,根本记不住

电子邮件的信息格式

邮件读取

基于万维网的电子邮件

万维网WWW

  • 万维网是一个大规模的、联机式的信息储藏所

  • 万维网用链接的方法可以非常方便地从互联网的一个站点访问另一个站点,这种访问方式称为“链接”

  • 万维网以C/S方式工作,浏览器是客户程序,万维网文档所在计算机运行服务器程序

URL

超文本传输协议HTTP

传输过程

  • 在万维网客户程序与万维网服务器程序之间进行交互的协议
  • 使用TCP连接
  • 每个万维网网点都有一个服务器进程,它不断地监听TCP的端口80,以便发现是否有浏览器向它发出连接建立请求
  • 一旦监听到连接建立请求并建立了TCP连接后,浏览器就向万维网服务器发出浏览某个页面的请求

HTTP报文格式

请求报文:

响应报文:

在原有的无状态的http协议上增添了功能

万维网cache和代理服务器

  • 在万维网中还可以使用缓存机制以提高万维网的效率
  • 万维网缓存也称为Web缓存,可位于客户机,亦可位于中间系统上(代理服务器)
  • Web缓存把最近的一些请求和响应暂存在本地磁盘中。当新请求到达时,若发现这个请求与暂时存放的请求相同,就返回暂存的响应,而不需要按照URL的地址去访问因特网的资源。

假设原始服务器的文档被修改,这时候代理服务器的文档就过期了。因此原始服务器通常会为每个响应的对象设置一个修改时间字段有效日期字段

若过期,但代理服务器的文档与原始服务器的文档一致,则原始服务器发送不带主体的响应:

若不一致,则需要发送封装有最新文档的报文:

完结撒花

来自《数据库系统概论(第6版)》第三章

基于Oracle 19数据库

SQL

模式的定义与删除

在数据库中,一个模式下通常包括多个表、视图和索引等数据库对象。一个数据库中可以建立多个模式。

在Oracle数据库中,模式的概念即用户

创建模式:

1
create user c##atri identified by xxxxxxxxx;

需在用户名前添加前缀C##

切换模式:

1
alter session set current_schema = c##atri;

删除模式:

1
DROP USER username CASCADE;

模式下包含的东西也被删除了。

基本表的建立

为了方便后续重点语句的展示,我这里按照书上的二维码,准备几个表。

sc.sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
DROP TABLE SC;
DROP TABLE Course;
DROP TABLE Student;
PURGE RECYCLEBIN;

CREATE TABLE Student
(
Sno CHAR(8) PRIMARY KEY,
Sname VARCHAR(20) UNIQUE,
Ssex CHAR(6),
Sbirthdate Date,
Smajor VARCHAR(40)
);

CREATE TABLE Course
(
Cno CHAR(5) PRIMARY KEY,
Cname VARCHAR(40) NOT NULL,
Ccredit SMALLINT,
Cpno CHAR(5),
FOREIGN KEY (Cpno) REFERENCES Course(Cno)
);

CREATE TABLE SC
(
Sno CHAR(8),
Cno CHAR(5),
Grade SMALLINT,
Semester CHAR(5),
Teachingclass CHAR(8),
PRIMARY KEY(Sno, Cno),
FOREIGN KEY(Sno) REFERENCES Student (Sno),
FOREIGN KEY(Cno) REFERENCES Course (Cno)
);

INSERT INTO Student values('20180001', '李勇', '男', DATE '2000-03-08', '信息安全');
INSERT INTO Student values('20180002', '刘晨', '女', DATE '1999-09-01', '计算机科学与技术');
INSERT INTO Student values('20180003', '王敏', '女', DATE '2001-08-01', '计算机科学与技术');
INSERT INTO Student values('20180004', '张立', '男', DATE '2000-01-08', '计算机科学与技术');
INSERT INTO Student values('20180205', '陈新奇', '男', DATE '2001-11-01', '信息管理与信息系统');
INSERT INTO Student values('20180306', '赵明', '男', DATE '2000-06-12', '数据科学与大数据技术');
INSERT INTO Student values('20180307', '王佳佳', '女', DATE '2001-12-07', '数据科学与大数据技术');

INSERT INTO Course values('81001', '程序设计基础与C语言', 4, NULL);
INSERT INTO Course values('81002', '数据结构', 4, '81001');
INSERT INTO Course values('81003', '数据库系统概论', 4, '81002');
INSERT INTO Course values('81004', '信息系统概论', 4, '81003');
INSERT INTO Course values('81005', '操作系统', 4, '81001');
INSERT INTO Course values('81006', 'Python语言', 3, '81002');
INSERT INTO Course values('81007', '离散数学', 4, NULL);
INSERT INTO Course values('81008', '大数据技术概论', 4, '81003');

INSERT INTO SC values('20180001', '81001', 85, '20192', '81001-01');
INSERT INTO SC values('20180001', '81002', 96, '20201', '81002-01');
INSERT INTO SC values('20180001', '81003', 87, '20202', '81003-01');
INSERT INTO SC values('20180002', '81001', 80, '20192', '81001-02');
INSERT INTO SC values('20180002', '81002', 98, '20201', '81002-01');
INSERT INTO SC values('20180002', '81003', 71, '20202', '81003-02');
INSERT INTO SC values('20180003', '81001', 81, '20192', '81001-01');
INSERT INTO SC values('20180003', '81002', 76, '20201', '81002-02');
INSERT INTO SC values('20180004', '81001', 56, '20192', '81001-02');
INSERT INTO SC values('20180004', '81003', 97, '20201', '81002-02');
INSERT INTO SC values('20180205', '81003', 68, '20202', '81003-01');

COMMIT;

表长这样:

关于修改表、删除表什么的,这里就摆了hh

索引的建立与删除

也摆了,Coming soon(???)

数据查询

单表查询

例子学习法,学习之前请先导入上面的sql文件

1
sql> @ $path_to_sc.sql

重点

(1)查询指定列

查询全体学生的学号与姓名

1
2
select sno, sname
from student;

(2)查询全部列

查询全体学生的详细记录

1
select * from student;

(3)查询经过计算的值

select子句的目标列表达式可以是算术表达式、字符串常量、函数

查询全体学生的年龄

1
2
select sname, (extract(year from current_date) - extract(year from sbirthdate)) "年龄"
from student;

查询全体学生的姓名、出生日期和主修专业

1
2
select sname, 'Date of birth:', sbirthdate, smajor
from student;

(4)消除取值重复的行

查询选修了课程的学生学号

1
select distinct sno from sc;

(5)查询满足条件的元组

比较:=,>,<,.>=,<=,!=,<>,!>,!<,NOT+

查询主修计算机科学与技术专业全体学生的姓名

1
2
3
select sname
from student
where smajor = '计算机科学与技术';

查询所有2000年后(包括2000年)出生的学生姓名及其性别

1
2
3
select sname, ssex
from student
where extract(year from sbirthdate) >= 2000;

查询考试成绩不及格的学生的学号

1
2
3
select distinct sno
from sc
where grade < 60;

确定范围:(not) between ... and ...

查询年龄在20~23岁(包括20岁和23岁)之间的学生的学生的姓名、出生年月和主修专业

1
2
3
select sname, sbirthdate, smajor
from student
where extract(year from current_date) - extract(year from sbirthdate) between 20 and 23;

查询年龄不在20~23岁(包括20岁和23岁)之间的学生的学生的姓名、出生年月和主修专业

1
2
3
select sname, sbirthdate, smajor
from student
where extract(year from current_date) - extract(year from sbirthdate) not between 20 and 23;

确定集合

谓词:in <值表>, not in <值表>

查询计算机科学与技术专业和信息安全专业学生的姓名和性别

1
2
3
select sname, ssex
from student
where smajor in ('计算机科学与技术', '信息安全');

字符匹配

[not] like '<匹配串>' [escape '<换码字符>']

%:任意长度(可以为0)的字符串

_:任意单个字符

查询学号为20180003的学生的详细情况

1
2
3
select *
from student
where sno like '20180003';

查询所有姓刘学生的姓名、学号和性别

1
2
3
select sname, sno, ssex
from student
where sname like '刘%';

查询2018级学生的学号和姓名

1
2
3
select sno, sname
from student
where sno like '2018%';

查询课程号为81开头,最后一位是6的课程名称和课程号

1
2
3
select cname, cno
from course
where cno like '81__6';

查询DB_Design课程的课程号和学分

1
2
3
select cno, ccredit
from course
where cname like 'DB\_Design' escape '\';

涉及空值的查询:is [not] NULL

is 不能用 = 代替

某些学生选修课程后没有参加考试,有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。

1
2
3
select sno, cno
from sc
where grade is null;

多重条件查询:and or,and优先级高于or

查询主修计算机科学与技术专业2000年(包括2000年)以后出生的学生学号、姓名和性别。

1
2
3
4
select sno, sname, ssex
from student
where smajor = '计算机科学与技术'
and extract(year from sbirthdate) >= 2000;

order by: 按一个或多个属性值升序(降序)排列,对于空值的实现依具体系统实现决定

查询选修了81003号课程的学生的学号及其成绩,查询结果按分数的降序排列

1
2
3
4
select sno, grade
from sc
where cno = '81003'
order by grade desc;

查询全体学生选修课程情况,查询结果先按照课程号升序排列,同一课程中按成绩降序排列。

1
2
select * from sc
order by cno, grade desc;

聚集函数

统计元组个数:count(*)

统计一列中值的个数:count([distinct|all] 列名)

计算一列值的总和(此列必须为数值型):sum([distinct|all] 列名)

计算一列值的平均值(此列必须为数值型):avg([distinct|all] 列名)

求一列中的最大值和最小值:max/min([distinct|all] 列名)

查询选修了课程的学生人数

1
2
select count(distinct sno)
from sc;

计算选修81001号课程的学生平均成绩

1
2
3
select avg(grade)
from sc
where cno = '81001';

查询选修1号课程的学生最高分数

1
2
3
select max(grade)
from sc
where cno = '81001';

查询学号为20180003学生选修课程的总学分数

1
2
3
select sum(ccredit)
from sc, course
where sno = '20180003' and sc.cno = course.cno;

group by子句分组:

  • 按指定的一列或多列值分组,值相等的为一组
  • 如果未对查询结果分组,聚集函数将作用于整个查询结果
  • 分组后,聚集函数将作用于每一个组

求各个课程号及选修该课程的人数

1
2
3
select cno, count(sno)
from sc
group by cno;

查询2019年第2学期选修了10门以上课程的学生学号

1
2
3
4
5
select sno
from sc
where semester = '20192'
group by sno
having count(*) > 10;

having 和 where 的区别:

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

limit:限制元组数量

查询选修了数据库系统概论课程的成绩排名前10名的学生学号

1
2
3
4
5
6
select sno
from sc, course
where course.cname = '数据库系统概论'
and sc.cno = course.cno
order by grade desc
limit 10;

limit关键字在oracle数据库是不支持的,需要用rownum来实现相同功能:

1
2
3
4
5
6
7
8
9
select * 
from(
select sno, grade
from sc, course
where course.cname = '数据库系统概论'
and sc.cno = course.cno
order by grade desc
)
where rownum <= 10;

连接查询

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

(1)等值与非等值连接查询

查询每个学生及其选修课程的情况

1
2
3
select student.*, sc.*
from student, sc
where student.sno = sc.sno;

(2)自然连接查询

查询每个学生的学号、姓名、性别、出生日期、主修专业及该学生选修课程的课程号与成绩

1
2
3
select student.sno, sname, ssex, sbirthdate, smajor, cno, grade
from student, sc
where student.sno = sc.sno;

(3)复合条件连接查询

在连接谓词的基础上增加选择谓词,组成复合条件

查询选修81002号课程且成绩在90分以上的所有学生的学号和姓名

1
2
3
4
5
select student.sno, sname
from student, sc
where student.sno = sc.sno
and sc.cno = '81002'
and sc.grade > 90;

(4)自身连接查询

查询每一门课的间接先修课(即先修课的先修课)

1
2
3
select first.cno, second.cpno
from course first, course second
where first.cpno = second.cno and second.cpno is not null;

(5)外连接查询

外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出。

以Student表为主体列出每个学生的基本情况及其选课情况,若某个学生没有选课,则只输出其基本情况的数据,而把选课信息填为空值NULL

1
2
select student.sno, sname, ssex, sbirthdate, smajor, cno, grade
from student left outer join sc on(student.sno = sc.sno);

(6)多表连接查询

两个以上的表的连接。

嵌套查询

  • 一个select-from-where语句称为一个查询块

  • 将一个查询块嵌套到另一个查询块的where子句或having短语的条件中的查询称为嵌套查询

  • 不相关子查询

子查询的查询条件不依赖于父查询,可以由里向外逐层处理。

  • 相关子查询

首先取外层查询表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若where返回真,则加入结果表。然后重复这一过程。

(1)IN谓词

查询与“刘晨”在同一个主修专业的学生学号、姓名和主修专业

1
2
3
4
5
6
7
select sno, sname, smajor
from student
where smajor in(
select smajor
from student
where sname = '刘晨'
);

查询选修了课程名为“信息系统概论”的学生的学号和姓名

1
2
3
4
5
6
7
8
9
10
11
select sno, sname
from student
where sno in(
select sno
from sc
where cno in(
select sno
from course
where cname = '信息系统概论'
)
);

(2)带有比较运算符的子查询

当能确切知道内层查询返回单值时,可用比较运算符。

找出每个学生超过他选修课程平均成绩的课程号

1
2
3
4
5
6
7
select sno, cno
from sc x
where grade >= (
select avg(grade)
from sc y
where x.sno = y.sno
);

先从外层的元组中取出x.sno,然后再内层中寻找y.sno=x.sno的元组,求avg(grade),用该值代替内层查询,重新得到外层查询。

(3)带有ANY(SOME)或ALL谓词

必须同时使用比较运算符

查询非计算机科学技术专业中比计算机科学技术专业任意一个学生年龄小(出生日期晚)的学生的姓名、出生日期和主修专业

1
2
3
4
5
6
7
8
select sname, sbirthdate, smajor
from student
where sbirthdate > any(
select sbirthdate
from student
where smajor = '计算机科学与技术'
)
and smajor <> '计算机科学与技术';

可以和一些聚集函数进行等价转换。

(4)EXISTS谓词

带有EXISTS谓词的子查询只产生逻辑真值 truefalse ,取决于内层查询是否非空。

查询没有选修81001号课程的学生姓名

1
2
3
4
5
6
7
select sname
from student
where not exists(
select *
from sc
where sno = student.sno and cno = '81001'
);

可用 exists/not exists 实现全称量词(难点): 查询选修了全部课程的学生姓名

1
2
3
4
5
6
7
8
9
10
11
select sname
from student
where not exists(
select *
from course
where not exists(
select *
from sc
where sno = student.sno and cno = course.cno
)
);

转换,不存在没有被该学生选修的课程,双重否定。

可用exists/not exists实现逻辑蕴涵(难点) 查询至少选修了学生20180002选修的全部课程的学生的学号

用逻辑蕴含来表达:查询学号为x的学生,对所有的课程y,只要20180002号学生选修了课程y,那么x也选修了y。

用p表示谓词“学生20180002选修了课程y”

用q表示谓词“学生x选修了课程y”

则上述查询为 .

可等价转换为 .

语义为:不存在(第一个not exists)这样的课程y,它即被20180002选修,但不被(第二个not exists)x选修。

1
2
3
4
5
6
7
8
9
10
11
12
select sno
from student
where not exists(
select *
from sc scx
where scx.sno = '20180002' and
not exists(
select *
from sc scy
where scy.sno = student.sno and scy.cno = scx.cno
)
);

其实我也不是很理解,这真的很抽象。

集合查询

UNION、INTERSECT、EXCEPT

查询计算机科学与技术专业的学生及年龄不大于19岁(包括等于19岁)的学生

1
2
3
4
select * from student where smajor = '计算机科学与技术'
union
select * from student
where (extract(year from current_date) - extract(year from sbirthdate)) <= 19;

查询计算机科学与技术专业的学生与年龄不大于19岁的学生的交集

1
2
3
4
select * from student where smajor = '计算机科学与技术'
intersect
select * from student
where (extract(year from current_date) - extract(year from sbirthdate)) <= 19;

基于派生表的查询

子查询不止可以出现在where子句中,还可以出现在from子句中。

找出每个学生超过他自己选修课程平均成绩的课程号

1
2
3
select sno, cno
from sc, (select sno as avg_sno, avg(grade) as avg_grade from sc group by sno) avg_sc
where sc.sno = avg_sc.avg_sno and sc.grade >= avg_sc.avg_grade;

数据更新


sql语言练习

首先运行该 emp.sql 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//SQL*PLUS里用@命令执行
//例如:假设此程序保存在D盘根目录下,.sql后缀可省略
// SQL> @D:\demo

DROP TABLE EMP;
DROP TABLE DEPT;
DROP TABLE BONUS;
DROP TABLE SALGRADE;


CREATE TABLE DEPT
(DEPTNO NUMBER(2),
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT dept_dname_uk UNIQUE (dname),
CONSTRAINT dept_deptno_pk PRIMARY KEY (deptno) );

INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO DEPT VALUES (40, 'OPERATIONS', 'BOSTON');

CREATE TABLE EMP
(EMPNO NUMBER(4) NOT NULL,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7, 2),
COMM NUMBER(7, 2),
DEPTNO NUMBER(2),
CONSTRAINT emp_empno_pk PRIMARY KEY (empno)
);

INSERT INTO EMP VALUES
(7369, 'SMITH', 'CLERK', 7902,
TO_DATE('17-12月-1980', 'DD-MON-YYYY'), 800, NULL, 20);
INSERT INTO EMP VALUES
(7499, 'ALLEN', 'SALESMAN', 7698,
TO_DATE('20-2月-1981', 'DD-MON-YYYY'), 1600, 300, 30);
INSERT INTO EMP VALUES
(7521, 'WARD', 'SALESMAN', 7698,
TO_DATE('22-2月-1981', 'DD-MON-YYYY'), 1250, 500, 30);
INSERT INTO EMP VALUES
(7566, 'JONES', 'MANAGER', 7839,
TO_DATE('2-4月-1981', 'DD-MON-YYYY'), 2975, NULL, 20);
INSERT INTO EMP VALUES
(7654, 'MARTIN', 'SALESMAN', 7698,
TO_DATE('28-9月-1981', 'DD-MON-YYYY'), 1250, 1400, 30);
INSERT INTO EMP VALUES
(7698, 'BLAKE', 'MANAGER', 7839,
TO_DATE('1-5月-1981', 'DD-MON-YYYY'), 2850, NULL, 30);
INSERT INTO EMP VALUES
(7782, 'CLARK', 'MANAGER', 7839,
TO_DATE('9-6月-1981', 'DD-MON-YYYY'), 2450, NULL, 10);
INSERT INTO EMP VALUES
(7788, 'SCOTT', 'ANALYST', 7566,
TO_DATE('09-12月-1982', 'DD-MON-YYYY'), 3000, NULL, 20);
INSERT INTO EMP VALUES
(7839, 'KING', 'PRESIDENT', NULL,
TO_DATE('17-11月-1981', 'DD-MON-YYYY'), 5000, NULL, 10);
INSERT INTO EMP VALUES
(7844, 'TURNER', 'SALESMAN', 7698,
TO_DATE('8-9月-1981', 'DD-MON-YYYY'), 1500, 0, 30);
INSERT INTO EMP VALUES
(7876, 'ADAMS', 'CLERK', 7788,
TO_DATE('12-1月-1983', 'DD-MON-YYYY'), 1100, NULL, 20);
INSERT INTO EMP VALUES
(7900, 'JAMES', 'CLERK', 7698,
TO_DATE('3-12月-1981', 'DD-MON-YYYY'), 950, NULL, 30);
INSERT INTO EMP VALUES
(7902, 'FORD', 'ANALYST', 7566,
TO_DATE('3-12月-1981', 'DD-MON-YYYY'), 3000, NULL, 20);
INSERT INTO EMP VALUES
(7934, 'MILLER', 'CLERK', 7782,
TO_DATE('23-1月-1982', 'DD-MON-YYYY'), 1300, NULL, 10);

CREATE TABLE BONUS
(ENAME VARCHAR2(10),
JOB VARCHAR2(9),
SAL NUMBER,
COMM NUMBER);

CREATE TABLE SALGRADE
(GRADE NUMBER,
LOSAL NUMBER,
HISAL NUMBER);

INSERT INTO SALGRADE VALUES (1, 700, 1200);
INSERT INTO SALGRADE VALUES (2, 1201, 1400);
INSERT INTO SALGRADE VALUES (3, 1401, 2000);
INSERT INTO SALGRADE VALUES (4, 2001, 3000);
INSERT INTO SALGRADE VALUES (5, 3001, 9999);


COMMIT;

(1)在emp表上添加如下约束:入职时间不得晚于2021年7月8日,工资不能为负值,deptno为emp的外码。

1
2
3
alter table emp add constraint hiredate_chk check(hiredate <= DATE '2021-07-08');
alter table emp add constraint salary_chk check(sal >= 0);
alter table emp add constraint deptno_forkey foreign key(deptno) references dept(deptno);

查询数据字典,可查看EMP表(需大写)所有约束。

(2)查询比他/她的经理工资高且雇佣时间长的雇员的雇员号、雇员名以及工资。

1
2
3
4
5
select a.empno, a.ename, a.sal
from emp a, emp b
where a.mgr = b.empno
and a.sal > b.sal
and a.hiredate < b.hiredate;

(3)查询雇佣人数最多的经理名。

1
2
3
4
5
6
7
8
9
10
11
12
select ename
from emp e1
where e1.empno = (
select mgr
from emp e2
group by e2.mgr
having count(*) = (
select max(count(*))
from emp e3
group by e3.mgr
)
);

(4)创建CS部门工资在4000~9000元间的姓“张”的雇员视图empv(eid, ename, salary)。

1
2
3
4
5
6
7
create view empv(eid, ename, salary) as
select empno, ename, sal
from emp, dept
where sal between 4000 and 9000
and ename like '张%'
and emp.deptno = dept.deptno
and dept.dname = 'CS';

(5)查询所有部门没有雇员的工资大于3000元的部门名。

1
2
3
4
5
6
7
8
select dname
from dept
where not exists(
select *
from emp
where emp.deptno = dept.deptno
and emp.sal > 3000
);

(6)查询与雇员“SMITH”同一职业的雇员号和雇员名。

1
2
3
4
5
6
7
select empno, ename
from emp
where job = (
select job
from emp e
where e.ename = 'SMITH'
);

(7)查询雇员工资最高的雇员号、雇员名和工资。

1
2
3
4
5
6
select empno, ename, sal
from emp e1
where e1.sal = (
select max(sal)
from emp e2
);

(8)删除“sales"部门的雇员信息。

1
2
3
4
5
delete from emp
where deptno = (
select deptno from dept
where dept.dname = 'SALES'
);

(9)修改7782号雇员的职业和部门号与7788号雇员相同。

1
2
3
4
5
6
7
update emp
set(job, deptno) = (
select job, deptno
from emp
where empno = 7788
)
where empno = '7782';

(10)创建一个函数,给定一个雇员号,返回该雇员所在部门比他/她工资高的雇员数目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
create or replace function get_higher_sal_cnt(p_empno in number)
return number
is
v_deptno emp.deptno%type;
v_sal emp.sal%type;
v_cnt number;
begin
select deptno, sal
into v_deptno, v_sal
from emp
where empno = p_empno;

select count(*)
into v_cnt
from emp
where deptno = v_deptno
and sal > v_sal;

return v_cnt;
end;
/

调用函数:

1
2
3
4
5
6
7
8
declare
v_empno number := 7782;
v_cnt number;
begin
v_cnt := get_higher_sal_cnt(v_empno);
DBMS_OUTPUT.PUT_LINE('number of higher-sal employees:' || v_cnt);
end;
/

计网——运输层复习

从通信和信息处理的角度看,运输层向其上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最底层

当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时,只有位于网络边缘部分的主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到三层(网络层)的功能。

从物理层到网络层,实现了主机到主机的通信。但实际上计网中通信的真正实体是位于通信两端主机中的进程如何为运行在不同主机上的应用进程提供直接的通信服务是运输层的任务,运输层协议又称为端到端协议

在运输层使用不同的端口,来对应不同的应用进程,然后通过网络层及其下层来传输应用层报文。接收方的运输层通过不同的端口,将收到的应用层报文,交付给应用层中相应的进程。这里的端口是指用来区分不同应用进程的标识符。

端口号

发送方的复用和接收方的分用

复用:多个进程利用一个运输层协议发送数据

分用:多个进程利用一个运输层协议接收数据

UDP和TCP

  • UDP和TCP是TCP/IP体系结构运输层的两个重要协议
  • 当运输层采用面向连接的TCP协议时,尽管下面的网络是不可靠的(例如无连接的数据报服务),但这种逻辑通信信道相当于一条全双工的可靠信道。TCP传输的数据单元是TCP报文段。
  • 但运输层采用无连接的UDP协议时,这种逻辑信道是一条不可靠信道。UDP传输的数据单元是UDP报文或用户数据报。

用户数据报协议UDP

UDP支持单播、多播以及广播

UDP对应用进程交下来的报文既不合并也不拆分,而是保留这些报文的边界,即UDP是面向应用报文的

UDP向上层提供无连接不可靠传输服务

UDP用户数据报结构如下:

是不是很简单?但是接下来的TCP会难到吐

传输控制协议TCP(Transmission Control Protocal)

使用TCP协议的通信双方,在进行数据传输之前,必须使用“三报文握手”建立TCP连接。TCP连接建立成功后,通信双方之间就好像有一条可靠的通信信道,通信双方使用这条基于TCP连接的可靠信道进行通信。

TCP只支持单播。

发送方

  • TCP会把应用进程交付下来的数据块看作是一串无结构的字节流,TCP并不知道这些字节流的含义
  • TCP会将字节流进行编号,并存储在自己的缓存中
  • TCP会根据发送策略,提取一定量的字节构建TCP报文并发送

接收方

  • 一方面从所接收到的TCP报文段中,取出数据载荷部分并存储在接收缓存中;另一方面将接收缓存中的一些字节交付给应用进程
  • TCP不保证接收方应用进程所收到的数据块与发送方发送的数据块具有对应大小的关系(例如,发送方应用进程给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块,就把收到的字节流交付给了上层的应用进程,但接收方的字节流必须和发送方的字节流完全一样
  • 接收方的应用进程必须有能力识别收到的字节流,并把它还原成有意义的应用层数据

TCP向上层提供面向连接的可靠传输服务

TCPの流量控制

所谓流量控制,就是让发送方的发送速率不要太快,要让接收方来得及接收。

TCP采用滑动窗口机制来实现对发送方的流量控制。

通过抄袭湖科大计网的例子来加深对流量控制的理解

首先,发送方维护一个400字节大小的滑动窗口,并将1-300号字节数据进行发送。但是201-300号字节的数据的TCP报文段丢失了。

此时,接收方对201号之前的数据进行累计确认,并将接收窗口大小(rwnd)调整为300。(报文段中ACK字段为1,代表报文段有意义)

接收方现在可在发送缓存中将前200字节的数据删除,因为已经收到了对应的累计确认。

201-300号字节的TCP报文段的超时重传计时器到时,发送方将其重传。

同时将发送窗口的剩余200个字节的数据进行发送。

接收方返回接收报文,对501号字节之前的数据进行累计确认,并将接收窗口大小调整为100。

发送方可将501号字节之前的数据从发送缓存中删除。

发送方将501-600号字节数据发送,接收方对601号以前的数据进行累计确认,并将接收窗口调整为0,让发送方不要再发了。

接收方现在想将接收窗口调整为300,但是该TCP报文丢失了。如果持续下去,将造成死锁

为了应对接收方死了的情况,发送方会同时维护一个持续计时器。只要发送方收到接收方的零窗口(rwnd=0)通知,就启动该计时器。若计时器超时,则会向接收方发送一个零窗口探测报文,对方收到该报文后会传回当前的接收窗口大小。若依然为0,则重新对持续计时器计时。

零窗口探测报文本身也有重传计时器,所以不用担心该报文丢失的情况。

TCPの拥塞控制

在某段时间,若对网络中某一资源(如带宽、交换节点的缓存、处理机等)的需求超过了该资源所能提供的可用部分,网络性能就会变差,这种情况叫做拥塞

若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降。

拥塞控制的一般原理:

  • 拥塞控制的前提:网络能够承受现有的网络负荷
  • 实践证明,拥塞控制是很难设计的,因为它是个动态问题
  • 分组的丢失是网络拥塞的征兆而不是原因
  • 在许多情况下,甚至正是拥塞本身成为引起网络性能恶化、甚至发生死锁的原因

拥塞控制的算法

真正的发送窗口值=min(接收方窗口值,拥塞窗口值)

传输轮次:

  • 发送方给接收方发送数据报文段后,接收方给发送方发回相应的确认报文段
  • 一个传输轮次所经历的时间其实就是往返时间,往返时间并非是恒定的数值
  • 使用传输轮次是为了强调把拥塞窗口所允许的报文段都连续发送出去,并收到了对已发送的最后一个报文段的确认

拥塞窗口:

  • 它会随网络拥塞程度

慢开始和拥塞避免

慢开始
  • 目的:用来确定网络的负载能力和拥塞程度
  • 算法思路:由小到大逐渐增大拥塞窗口数值
  • 两个变量
    • 拥塞窗口(cwnd)
    • 慢开始门限(ssthresh)

每经过一个传输轮次,拥塞窗口就加倍

窗口大小按指数增加

拥塞避免
  • 思路:让拥塞窗口cwnd缓慢地增大,避免出现拥塞

  • 每经过一个传输轮次,拥塞窗口cwnd++

  • cwnd按线性规律缓慢增长

如果在发送过程中出现部分报文段丢失,这会引起发送方对这些报文段的超时重传

此时会判断网络出现拥塞,将ssthresh减为当前cwnd值的一半,并将cwnd重新设为1,开始慢开始算法。

细节,慢开始cwnd *=2 时需要和ssthresh取min。

快重传和快恢复

增加的两个新的拥塞控制算法,改进TCP的性能

快重传

就是在超时重传的时限前,找机会提前把丢失的报文重传了,如果重传成功的话,说明网络没有出现拥塞,从而防止cwnd降为1并重启慢开始算法.

快恢复
四个拥塞避免算法总览

TCP超时重传时间选择

emmm,好像不考欸,至少王道书上没有

TCP可靠传输的实现

TCP基于以字节为单位的滑动窗口来实现可靠传输。

使用三指针来维护窗口状态

虽然发送方的发送窗口是根据接收方的接收窗口设置的,但在同一时刻,发送方的发送窗口并不一定总是和接收方的接收窗口一样大。

  • 网络传送窗口值需要一段时间的时间滞后
  • 发送方可能还需要根据拥塞情况减小自己的发送窗口尺寸

对于不按序到达的数据的处理,TCP并无明确规定。

TCP要求接收方必须要有累计确认和捎带确认机制,这样可以减少传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。

  • 接收方不应过分推迟发送确认,否则会造成不必要的超时重传。
  • 捎带确认很少使用,因为大多数应用程序很少同时在两个方向上发送数据。

TCP的通信是全双工通信。

TCP的运输连接管理

TCPの连接建立

  • TCP建立连接的过程叫做握手
  • 握手需要在客户和服务器之间交换三个TCP报文段。称之为三报文握手
  • 采用三次握手主要是为了防止已失效的连接请求报文段突然又传送到了,继而产生错误。

TCP的连接建立要解决以下三个问题:

  • 使TCP双方能够确知对方的存在
  • 使TCP双方能够协商一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)
  • 使TCP双方能够对运输实体资源(如缓存大小、连接表中的项目)进行分配

TCP使用三报文握手建立连接。

  • TCP连接的建立采用客户服务器方式
  • 主动发起连接建立的应用进程叫做TCP客户
  • 被动等待连接建立的应用进程叫做TCP服务器

过程

最初两端的TCP进程都处于关闭状态。

一开始,TCP服务器进程首先创建传输控制块,用来存储TCP连接中的一些重要信息,例如TCP连接表、指向发送和接收缓存的指针、指向重传队列的指针,当前的发送和接受序号等

之后,就准备接受TCP客户端进程的连接请求

此时TCP服务器进程就进入监听状态,等待TCP客户端进程的连接请求。

TCP服务器进程是被动等待来自TCP客户端进程的连接请求,因此称为被动打开连接。

TCP客户进程也是首先创建传输控制块。

由于TCP连接建立是由TCP客户端主动发起的,因此称为主动打开连接。

然后,在打算建立TCP连接时,向TCP服务器进程发送TCP连接请求报文段,并进入同步已发送状态。

在TCP连接请求报文段的首部中

  • 同步位SYN被设置为1,表明这是一个TCP连接请求报文段
  • 序号字段seq被设置了一个初始值x,作为TCP客户端进程所选择的初始序号

请注意:TCP规定SYN被设置为1的报文段不能携带数据,但要消耗掉一个序号

TCP服务器进程收到TCP连接请求报文段后,如果同意建立连接,则向TCP客户进程发送TCP连接请求确认报文段,并进入同步已接收状态。

TCP连接请求确认报文段的首部中

  • 同步位SYN和确认位ACK都设置为1,表明这是一个TCP连接请求确认报文段
  • 序号字段seq被设置了一个初始值y,作为TCP服务器进程所选择的初始序号
  • 确认号字段ack的值被设置为了x+1,这是对TCP客户进程所选择的初始序号(seq)的确认

请注意:这个报文段由于SYN被设置为1,因而也不能携带数据,但也要消耗掉一个序号

TCP客户进程收到TCP连接请求确认报文段后,还需要向TCP服务器进程发送一个普通的TCP确认报文段,并进入连接已建立状态。

普通的TCP确认报文段首部中

  • 确认位ACK被设置为1,表明这是一个普通的TCP确认报文段
  • 序号字段seq被设置为x+1,这是因为TCP客户进程发送的第一个TCP报文段的序号为x,所以TCP客户进程发送的第二个报文段的序号为x+1
  • 确认号ack被设置为y+1,这是对TCP服务器进程所选择的初始序号的确认

请注意:TCP规定普通的TCP确认报文段可以携带数据,但如果不携带数据,则不消耗序号

TCP服务器进程收到该确认报文段后也进入连接已建立状态。

现在,TCP双方都进入了连接已建立状态,它们可以基于已建立好的TCP连接,进行可靠的数据传输

TCP连接建议需要第三个报文段:普通确认报文段的目的

为了防止这种情况:客户端进程发出去的第一个连接请求报文段并没有丢失,而因为某些原因,在网络上发生滞留。结果在整个TCP连接建立且释放后,该报文段才到达TCP服务器进程,这会导致TCP服务器进程错误地进入了连接已建立状态,造成资源浪费。

本质上是TCP服务器进程收到一次连接请求报文就建立连接而造成的资源浪费建立,而如果使用三报文握手的话,就要求TCP服务器进程需要收到两个请求报文,这能有效地防止上述情况的发生。

TCPの连接释放

TCP通过四报文挥手来释放连接。

  • TCP连接的释放采用客户服务器方式
  • 任何一方都可以在数据传送结束后发出连接释放的通知

首先通信双方处于连接已建立状态

TCP客户进程的应用进程通知其主动关闭TCP连接

TCP客户进程会发送TCP连接释放报文段,并进入终止等待1状态。

TCP连接释放报文段首部中

  • 终止位FIN和确认位ACK的值都被设置为1,表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认
  • seq字段的值设置为u,它等于TCP客户进程之前已传送过的数据的最后一个字节的序号+1
  • ack的值被设置为v,它等于TCP客户进程已收到的数据的最后一个字节的序号+1

请注意:TCP规定终止位FIN等于1的报文段即使不携带数据,也要消耗掉一个序号

TCP服务器进程收到TCP连接释放报文段后,会发送一个普通的TCP确认报文段并进入关闭等待状态。

普通的TCP确认报文段首部中

  • ACK被设置为1,表明这是一个普通的TCP确认报文段
  • seq被设置为v,它等于TCP服务器进程之前已传送的数据的最后一个字节的序号+1,这也与之前收到的TCP连接释放报文段的ack值匹配
  • ack的值被设置为u+1,这是对TCP连接释放报文段的确认

此时TCP服务器进程应该通知高层应用进程,TCP客户进程要断开和自己的连接

此时,从TCP客户进程到TCP服务器进程这个方向的连接就释放了

此时TCP连接属于半关闭状态,这是因为TCP服务器进程可能还有数据要发送,也就是说反方向的连接并未关闭

TCP客户进程收到TCP确认报文段后就进入终止等待2状态,等待TCP服务器进程发出的TCP连接释放报文段

若TCP服务器进程没有数据要发送了,TCP服务器进程就会释放连接,这时TCP服务器进程就会发送TCP连接释放报文段并进入最后确认状态

该报文段首部中

  • 终止位FIN和确认位ACK的值都被设置为1,表明这是一个TCP连接释放报文段
  • seq的值为w,这是因为半关闭状态下,服务器进程可能继续发送了一些数据
  • ack的值为u+1,这是对之前收到的连接释放报文段的重复确认

TCP客户进程收到TCP连接释放报文段后,必须针对该报文段发送普通的TCP确认报文段,之后进入时间等待状态。

该报文段首部中

  • 确认位ACK的值被设置为1,表明这是一个普通的TCP确认报文段
  • seq被设置为u+1,这是因为TCP客户进程之前发送的TCP连接释放报文段虽然不携带数据,但是要消耗掉一个序号
  • ack被设置为w+1,这是对所收到的TCP连接释放报文段的确认

TCP服务器进程收到该报文段后就进入关闭状态,而TCP客户进程还需要经过2MSL后才能进入关闭状态。

时间等待状态可以确保TCP服务器进程可以收到最后一个TCP确认报文段而进入关闭状态,且在该2MSL时长里,可以使本次连接持续时间内所产生的报文段都从网络中消失,这样在新的TCP连接中,不会出现旧连接的报文段。

TCP保活计时器

TCP双方已建立连接,然而TCP客户进程所在主机出现了故障

TCP服务器进程以后不能再收到TCP客户端进程发来的数据

因此,需要有措施让服务器不白白等下去

TCP报文段首部格式

源、目的端口

序号、确认号、确认标志位ACK

数据偏移(首部长度)、保留、窗口和校验和

同步标志位SYN、终止标志位FIN、复位标志位RST、推送标志位PSH、紧急标志位URG、紧急指针

选项和填充

来自《数据库系统概论(第6版)》第二章

关系代数

假设关系 具有相同的目 ,且相应的属性取自同一个域, 是元组变量。

关系 的并记作 其结果仍是 目关系,由属于 的元组组成。

关系 的差记作 其结果仍是 目关系,由属于 而不属于 的元组组成。

关系 的交记作 它不是基本运算,因为可以转化:。画个van图就知道怎么回事。

  • (广义)笛卡尔积

加上"广义"的原因是这里笛卡尔积的元素是元组。

两个分别为 目和 目的关系 和关系 的笛卡尔积是一个 列元组的集合: 这玩意就是个排列组合。

  • 选择

在关系 中选择满足给定条件的诸元组(选行):

  • 投影

关系 上的投影是从 中选择若干属性列组成新的关系(选列):

  • 连接

两个关系的笛卡儿积中选取其属性间满足一定条件的元组: 等值连接:从关系 中选取广义笛卡儿积中A、B属性值相等的那些元组。

自然连接:特殊的等值连接,要求两个关系中进行比较的分量必须是同名的属性列,且在结果中将重复的属性列去掉。直接用 表示。

设关系 除以关系 的结果为关系 ,则 包含所有在 但不在 中的属性及其值,且 的元组与 的元组的所有组合都在 中。 其中 中的象集。

象集:给定一个关系 。当 时, 中的象集为:

可以理解为对于一个给定的取值 ,其对应的在关系 的取值的集合。

然后除运算就是指所有满足其在关系 的取值的集合能够包含关系 中所有 取值集合所对应的关系 中的

一些例题

试用关系代数完成如下查询:

查询李勇同学选修的课程中考试及格的课程名。 查询既选修了2号课程又选修了3号课程的学生的学号和姓名。 查询只选修了1门课程的学生的学号和姓名。

关系演算

元组关系演算语言ALPHA

  • 检索操作

最难的操作

语句格式:GET 工作空间名【(定额)】 (表达式1)【:操作条件】【DOWN/UP 表达式2】

根本看不懂,这里举几个例子

还是这三张表

(1)简单检索

查询所有被选修的课程的课程号: 查询所有学生的数据: (2)限定的检索(带条件)

查询信息系(IS)中年龄小于20岁的学生的学号和年龄: (3)带排序的检索

查询计算机科学系(CS)学生的学号、年龄,结果按年龄降序排序: (4)带定额的检索

取出一个信息系学生的学号: 查询信息系年龄最大的三个学生的学号及其年龄,结果按年龄降序排序: (5)用元组变量的检索

元组变量:表示可以在某一关系范围内变化

用途:1、简化关系名;2、操作条件中使用量词()时必须用元组变量。

定义元组变量:关系名 变量名

一个关系可以设多个元组变量

(6)用存在量词的检索

查询选修2号课程的学生名字。 查询选修了这样课程的学生学号,其直接先行课是6号课程。 查询至少选修一门其先行课为6号课程的学生名字。 (前束范式形式)

(7)带有多个关系的表达式的检索

查询成绩为90分以上的学生名字与课程名字。 (8)用全称量词的检索

查询不选1号课程的学生名字。

是不是有点抽象,其实一般人应该会这么写:

可以从下式转换为上式(存在量词转化为全称量词)。但是可以理解上式的含义:选定Student表的一行,对于表SC中的每一个条目,要么学号不为Student表所对应的学号,要么等于对应的学号,但是都满足课程号不为1.

(9)用两种量词的检索

查询选修了全部课程的学生姓名。

有点抽象,这里我理一下。

首先,我们固定表Student的一个元组,然后对该元组进行判断:

1、对于表Course的所有项,都存在表SC的一项,满足二者的Cno相同

2、然后对于存在的表SC的这一项,都需要满足它和表Student所固定元组的Sno相同

所有题目的思路都应该是这样的:固定GET W里的变量,然后判断条件是否为真

(10)用蕴含的检索

查询最少选修了201215122学生所选课程的学生学号。

求解思路是这样的:首先固定Student.Sname

然后对Course的每一门课程,看它是否被201215122选,如果选了的话,再判断是否也被Student对应学生选。这是一个蕴含关系。

(11)聚集函数

函数名 功能
COUNT 对元组计数
TOTAL 求总和
MAX 求最大值
MIN 求最小值
AVG 求平均值

查询学生所在系的数目: 查询信息系学生的平均年龄:

一些例题

呃呃呃,还是这三个表:

试用元组关系演算语言ALPHA完成如下查询:

查询李勇同学选修的课程中考试及格的课程名。 查询既选修了2号课程又选修了3号课程的学生的学号和姓名。 查询所有选修课程均不及格的学生的学号和姓名。

这里要把一门课都没选的学生给排除掉

  • 修改操作

修改操作用UPDATE语句实现,其步骤是:

  1. 用HOLD语句将要修改的元组从数据库读到工作空间中
  2. 用宿主语言修改工作空间中元组的属性值
  3. 用UPDATE语句将修改后的元组送回数据库

把201215121学生从计算机科学系转到信息系。

  • 插入操作

插入操作用PUT语句实现,其步骤是:

  1. 用宿主语言在工作区间中建立新元组
  2. 用PUT语句把该元组插入指定的关系

学校新开设了一门2学分的课程“计算机组织与结构”,其课程号为8,直接先行课为6号课程。插入该课程元组

  • 删除操作

删除操作用DELETE语句实现,其步骤是:

  1. 用HOLD语句把要删除的元组从数据库读到工作空间中
  2. 用DELETE语句删除该元组

201215125学生因故退学,删除该学生元组


补充一些关于关系数据库的小知识点

关系模型中三类完整性约束:

  • 实体完整性
  • 参照完整性
  • 用户定义的完整性

实体完整性:若属性A是基本关系R的主属性,则属性A不能取空值

一个基本表通常对应现实世界的一个实体集多对多联系。现实世界的实体和实体间的联系都是可区分的,即它们具有某种唯一的标识,而在关系模型中,这种唯一的标识即主码,它需要保证非空,来确保所对应的实体是完整的,独一无二的。

外码:设F是基本关系R的一个或一组属性,但不是关系R的码。是基本关系S的主码。如果F与基本关系S的主码 对应,则称F是基本关系R的外码。并称基本关系R为参照关系,S为被参照关系。(R与S可能是同一个关系)

参照完整性:若属性F是基本关系R的外码,它与基本关系S的主码 对应,则对于R中的每个元组在F上的取值必须为:

  • S中某个元组的主码值

用户定义的完整性:略

下课了喵

0%