整理自中国人民大学的慕课《数据库系统概论》,课程链接如下
https://www.icourse163.org/course/RUC-1001655006?from=searchPage
没有一个数据库系统能够支持SQL标准的所有概念和特性
综合统一
SQL 高度非过程化
面向集合的操作方式
操作对象、查找结果可以是元组的集合
一次插入、删除、更新操作的对象可以是元组的集合
语言简洁,易学易用
SQL功能 | 动词 |
---|---|
数据查询 | SELECT |
数据定义 | CREATE, DROP, ALTER |
数据操纵 | INSERT, UPDATE, DELETE |
数据控制 | GRANT, REVOKE |
SQL支持关系数据库的三级模式结构
基本表
存储文件
操作对象 | 操作方式 | ||
---|---|---|---|
创建 | 删除 | 修改 | |
模式 | CREATE SCHEMA | DROP SCHEMA | |
表 | CREATE TABLE | DROP TABLE | ALTER TABLE |
视图 | CREATE VIEW | DROP VIEW | |
索引 | CREATE INDEX | DROP INDEX | ALTER INDEX |
数据字典
定义模式
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>[<表定义子句>|<视图定义子句>|<授权定义子句>]
--为用户WANG定义一个学生-课程模式S-T
CREATE SCHEMA "S-T" AUTHORIZATION WANG;
--<模式名>缺省,隐含为<用户名>
CREATE SCHEMA AUTHORIZATION WANG;
删除模式
DROP SCHEMA <模式名> <CASCAD|RESTRICT>
定义基本表
CREATE TABLE <表名>
(<列名><数据类型>[<列级完整性约束条件>]
[,<列名><数据类型>[<列级完整性约束条件>]
...
[,<表级完整性约束条件>];
CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY,
Sname CHAR(20) UNIQUE,
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20)
);
CREATE TABLE Course
(Cno CHAR(4) PRIMARY KEY,
Cname CHAR(40),
Cpno CHAR(4),
Ccredit SMALLINT,
FOREIGN KEY(Cpno) REFERENCES Course(Cno)
);
CREATE TABLE SC
(Sno CHAR(9),
Cno CHAR(4),
Grade SMALLINT,
PRIMARY KEY(Sno, Cno),
FOREIGN KEY(Sno) REFERENCE Student(Sno),
FOREIGN KEY(Cno) REFERENCES Course(Cno)
);
修改基本表
ALTER TABLE<表名>
[ADD [COLUMN] <新列名> <数据类型> [完整性约束]]
[ADD <表级完整性约束>]
[DROP [COLUMN] <列名> [CASCADE|RESTRICT]]
[DROP CONSTRAINT <完整性约束名> [RESTRICT|CASCADE]
[ALTER COLUMN <列名> <数据类型>];
--增加入学时间列
ALTER TABLE Student ADD S_entrance DATE;
--将年龄的数据类型改为整数型
ALTER TABLE Student ALTER COLUMN Sage INT;
--增加课程名称必须取唯一值的约束条件
ALTER TABLE Course ADD UNIQUE(Cname);
删除基本表
DROP TABLE <表名> [RESTRICT|CASCADE]
RESTRICT : 要删除的基本表不能被其他表的约束所引用,如果存在依赖该表的对象,则此表不能被删除
CASCADE :删除该表没有限制,在删除基本表的同时,相关的依赖对象一起删除
索引的定义
CREATE UNIQUE INDEX Stusno ON Student(Sno);
CREATE UNIQUE INDEX Coucno ON Course(Cno);
--按学号升序和课程号降序建立唯一索引
CREATE UNIQUE INDEX SCno ON SC(Sno ASC, Cno DESC);
- 修改索引
ALTER INDEX <旧索引名> RENAME TO <新索引名>
ALTER INDEX SCno RENAME TO SCSno;
- 删除索引
ALTER INDEX <索引名>;
DROP INDEX Stusno;
SELECT 子句 | 指定要显示的属性列 |
FROM 子句 | 指定查询对象(基本表或视图) |
WHERE 子句 | 指定查询条件 |
– | – |
GROUP BY 子句 | 对查询结果按指定列的值分组,该属性列值相等的元组为一个组。通常在每组中作用聚集函数 |
HAVING 短语 | 只有满足指定条件的组才予以输出 |
– | – |
ORDER BY 子句 | 对查询结果表按指定列值的升序或降序排序 |
SELECT [ALL|DISTINCT] <目标列表达式> [,<目标列表达式>]...
FROM <表名或视图名> [,<表名或视图名>]...|(SELECT 语句)
[AS] <别名>
[WHERE <条件表达式>]
[GROUP BY <列名1> [HAVING <条件表达式>]]
[GROUP BY <列名2> [ASC|DESC]];
--查询全体学生的学号和姓名
SELECT Sno, Sname FROM Student;
--查询全部列
SELECT * FROM Student;
--查询经过计算的值
SELECT Sname, 2016-Sage FROM Student;
--小写字母表示系名LOWER()
SELECT Sname,'Year of Birth:',2014-Sage,LOWER(Sdept) FROM Student
--使用列别名改变查询结果的列标题
SELECT Sname, 'Year of Brith:' BIRTH, 2014-Sage BIRTHDAY, LOWER(Sdept) DEPARTMENT FROM Student
查询条件 | 谓词 |
---|---|
比较 | =, >, <, >=, <=, !>, !<; NOT +上述比较运算符 |
确定范围 | BETWEEN AND, NOT BETWEEN AND |
确定集合 | IN NOT IN |
字符比配 | LIKE, NOT LIKE |
空值 | IS NULL, IS NOT NULL |
逻辑运算 | AND, OR, NOT |
--查询计算机系全体学生的名单
SELECT Sname FROM Student WHERE Stept = 'CS';
--查询所有年龄在20岁以下的学生姓名及其年龄
SELECT Sname,Sage FROM Student WHERE Sage < 20;
--查询考试成绩有不及格的学生的学号
SELECT DISTINCT Sno FROM SC WHERE Grade < 60;
--查询年龄在20-23岁之间(包括20,23)
SELECT Sname, Sdept, Sage FROM Student WHERE Sage BETWEEN 20 AND 23;
--查询CS,MA,IS学生的姓名和性别
SELECT Sname, Ssex FROM Student WHERE Stept in ('CS','MA','IS');
--查询学号为201215121的学生的详细情况(匹配固定)
SELECT * FROM Student WHERE Sno LIKE '20121521';
--匹配串包含通配符%(多个字符)或_(单个字符)
SELECT Sname, Ssex FROM Student WHERE Sname LIKE '刘%';
SELECT Sname, Ssex FROM Student WHERE Sname LIKE '欧阳_';
--使用换码字符将通配符转义为普通字符
SELECT Cno, Ccredit FROM Course WHERE Cname LIKE 'DB\_DESIGN' ESCAPE'\';
'--查询以'DB_'开头且倒数第三个字符为'i'的课程'
SELECT * FROM Course WHERE Cname LIKE 'DB\_%__'ESCAPE'\';
'--IS不能用 =代替
SELECT * FROM SC WHERE Grade IS NULL;
--查询计算机系年龄20以下的学生姓名--
SELECT Sname FROM Student WHERE Sdept = 'CS'AND Sage < 20;
-- 从表SC中选取学号Sno和成绩Grade满足条件 课程号Cno = '3'按照 成绩Grade降序排列
SELECT Sno, Grade FROM SC WHERE Cno = '3' ORDER BY Grade DESC;
--查询结果按照系号升序排列,同一系中按照年龄降序
SELECT * FROM Student ORDER BY Sdept, Sage DESC;
聚集函数
1. 统计元组个数 COUNT(*)
2. 统计一列中值的个数 COUNT([DISTINCT|ALL] <列名>)
3. 统计一列值的总和 SUM([DISTINCT|ALL] <列名>)
4. 统计一列值的平均值 AVG([DISTINCT|ALL] <列名>)
5. 求一列值中的最大值和最小值 MAX([DISTINCT|ALL] <列名>); MIN([DISTINCT|ALL] <列名>)
WHERE 子句中不能用聚集函数作为条件表达式,WHERE 子句表示对记录的限制,而不是对组的限制。正确做法是使用HAVING 短语。
SELECT COUNT(*) FROM Student;
--查询了选修课程的学生人数
SELECT COUNT(DISTINCT Sno) FROM Student;
--计算‘1’号课程的学生平均成绩
SELECT AVG(Grade) FROM SC WHERE Cno = '1';
--计算‘1’号课程的学生zu最高成绩
SELECT MAX(Grade) FROM SC WHERE Cno = '1';
--查询学生201212012选修课程的总学分数
SELECT SUM(Ccredit) FROM SC, Course WHERE Sno = '201212012' AND SC.Cno = Course.Cno;
--求各个课程号及相应的选课人数(先group,再count)
SELECT Cno, COUNT(Sno) FROM SC GROUP BY Cno;
--查询选修了3们以上课程的学生学号
SELECT Sno FROM SC GROUP BY Sno HAVING COUNT(*)>3;
--查询平均成绩大于90分的学生学号和平均成绩
SELECT Sno, AVG(Grade) FROM SC GROUP BY Sno HAVING AVG(Grade) > 90;
--按系并区分男女统计各系学生人数,并按照人数降序排序
SELECT Sdept, Ssex, COUNT(Sno) FROM Student GROUP BY Sdept, Ssex ORDER BY COUNT(Sno) DESC;
--查询每个学生及其选修课程的情况
SELECT Student.*, SC.* FROM Student, SC WHERE Student.Sno = SC.Sno;
--自然连接,在SELECT中去除重复字段
SELECT Student.Sno, Sname, Ssex, Sdept, Cno, Grade
FROM Student, SC
WHERE Student.Sno = SC.Sno;
连接操作的三种方法
一条SQL语句可以同时完成选择和连接查询,这时WHERE子句是由连接谓词和选择谓词组成的复合条件
--查询选修2号课程且成绩在90分以上的所有学生的学号和姓名
SELECT Student.Sno, Sname FROM Student, SC WHERE Student.Sno = SC.Sno AND SC.Cno = '2' AND SC.Grade > 90
--查询每一门课的直接先修课的名称
SELECT FIRST.Cname, SECOND.Cname FROM Course FIRST, Course SECOND WHERE FIRST.Cpno = SECCOND.Cno;
--左外连接
SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade FROM Student LEFT OUT JOIN SC ON (Student.Sno = SC.Sno);
--商业系统的表达,左外连接(+)
SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade FROM Student, SC WHERE Student.Sno (+) = SC.Sno;
--查询每个学生的学号、姓名、选修的课程以及成绩
SELECT Student.Sno, Sname, Cname, Grade FROM Student, SC, Course WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno;
嵌套查询
1. 一个SELECT-FROM-WHERE语句称为一个查询块
2. 将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询
SQL 语言允许多层嵌套查询
子查询的限制:不能使用ORDER BY 语句
SELECT Sname /*外层查询/父查询*/
FROM Student
WHERE Sno IN
(SELECT Sno /*内层查询/子查询*/
FROM SC
WHERE Cno = '2'
);
不相关子查询:子查询的查询条件不依赖于父查询
由里向外逐层处理。即把每个子查询在上一级查询处理之前求解,子查询的结果用于建立父查询的查找条件
相关子查询:子查询的查询条件依赖于父查询
首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表
然后再取外层表的下一个元组
重复这一过程,直到外层表全部检查完为止
--带有IN谓词的子查询 ; 不相关子查询
SELECT Sno, Sname, Sdept FROM Student
WHERE Sdept IN
(SELECT Sdept FROM Student WHERE Sname = '刘晨');
--用自身连接完成
SELECT S1.Sno, S1.Sname, S1.Sdept
FROM Student S1, Student S2
WHERE S1.Sdept = S2.Sdept AND S2.Sname = '刘晨';
--查询选修了课程名为‘信息系统’的学生学号和姓名
SELECT Sno, Sname FROM Student
WHERE Sno IN
(SELECT Sno FROM SC
WHERE Cno IN
(SELECT Cno FROM Course
WHERE Cname = '信息系统'
)
);
--连接实现
SELECT Sno, Sname FROM Student, SC, Course
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno AND Course. Cname = '信息系统';
SELECT Sno, Sname, Sdept FROM Student
WHERE Sdept =
(SELECT Sdept FROM Student WHERE Sname = '刘晨');
--找出每个学生超过他选修课平均成绩的课程号,相关子查询
SELECT Sno, Cno FROM SC x WHERE Grade >= (SELECT AVG(Grade) FROM SC y WHERE y.Sno = x.Sno);
带有ANY(SOME ) 或ALL 谓词的子查询
引入ANY 和ALL谓词,其对象为某个查询结果,表示其中任意一个值或者全部值
使用ANY 或ALL谓词时必须同时使用比较运算符
--查询非CS系中比CS系中一个学生年龄小的学生姓名和年龄
SELECT Sname, Sage FROM Student WHERE Sage < ANY (SELECT Sage FROM Student WHERE Sdept = 'CS')
AND Sdept <> 'CS';
SELECT Sname, Sage FROM Student WHERE Sage < (SELECT MAX(Sage) FROM Student WHERE Sdept = 'CS')
AND Sdept <> 'CS';
--查询非CS系中比CS系中所有学生年龄小的学生姓名和年龄
SELECT Sname, Sage FROM Student WHERE Sage < ALL (SELECT Sage FROM Student WHERE Sdept = 'CS')
AND Sdept <> 'CS';
SELECT Sname, Sage FROM Student WHERE Sage < (SELECT MIN(Sage) FROM Student WHERE Sdept = 'CS')
AND Sdept <> 'CS';
带有EXISTS谓词的子查询
引入EXIST谓词,其对象也是某个查询结果。
若内层查询结果非空,则外层的WHERE 子句返回真值
若内层查询结果为空,则外层的WHERE 子句返回假值
--查询选修了一号课程的学生姓名
SELECT Sname FROM Student WHERE EXISTS
(SELECT * FROM SC WHERE Sno = Student.Sno AND Cno = '1');
--查询没有选修一号课程的学生姓名
SELECT Sname FROM Student WHERE NOT EXISTS
(SELECT * FROM SC WHERE Sno = Student.Sno AND Cno = '1')
--查询了至少选修了学生2012211选修的全部课程的学生号码
--即 不存在这样的课程y,学生2021211选修了,而学生X没有选
SELECT DISTINCT SCX.Sno FROM SC SCX
WHERE NOT EXISTS
(SELECT * FROM SC Y WHERE SCY.Sno = '2012211' AND
NOT EXISTS
(SELECT * FROM SC SCZ WHERE SCZ.Sno = SCX.Sno AND SCZ.Cno = SCY.Cno));
集合查询
并操作 UNION
交操作 INTERSECT
差操作 EXCEPT
UNION 自动去除重复元组
UNION ALL 保留重复元组
SELECT * FROM Student WHERE Sdept = 'CS'
UNION
SELECT * FROM Student WHERE Sage <= 19;
空值处理
INSERT INTO Student (Sno, Sname, Ssex, Sdept, Sage) VALUES ('2012211','晨晨','男','IS',18);
--求平均年龄,存入数据库
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;
DBMS在执行插入语句时会检查所插元组是否会破坏表上已定义的完整性规则
1.实体完整性
2.参照完整性
3.用户定义的完整性
NOT NULL 约束
UNIQUE 约束
值域约束
修改数据
UPDATE <表名> SET <列名> = <表达式> [,<列名> = <表达式>]... [WHERE <条件>];
UPDATE Student SET Sage = 22 WHERE Sno = '201215121';
UPDATE SC SET Grade = 0 WHERE Sno IN (SELECT Sno FROM Student WHERE Sdept = 'CS');
DELETE FROM <表名> [WHERE <条件>];
--删除一个元组
DELETE FROM Student WHERE Sno = '2012111';
--删除多个元组
DELETE FROM SC;
--带子查询的删除语句
DELETE FROM SC WHERE Sno IN (SELECT Sno FROM Student WHERE Sdept = 'CS');
定义视图
-- 组成视图的属性列名:全部省略或全部指定
CREATE VIEW <视图名> [(<列名> [, <列名>]...)]
AS <子查询>
[WITH CHECK OPTION];
--缺点:使用 (SELECT * )修改基表Student的结构后,表与视图的映象关系被破坏,导致改视图不能正常工作
CREATE VIEW F_Student(F_Sno, name, sex, age, dept)
AS SELECT * /*不指定属性列*/
FROM Student WHERE Ssex = '女';
--加上WITH CHECK OPTION 子句,对该视图进行增删改操作,DBMS会自动加上 Sdept = 'IS'的条件
CREATE VIEW IS_Student
AS SELECT Sno, Sname, Sage FROM Student WHERE Sdept = 'IS'
WITH CHECK OPTION;
--基于多个表的视图
--建立选修了1号课程的学生的视图
CREATE VIEW IS_S1(Sno, Sname, Grade)
AS SELECT Student.Sno, Sname, Grade FROM Student, SC
WHERE Sdept = 'IS' AND Student.Sno = SC.Sno AND SC.Cno = '1'
WITH CHECK OPTION;
--基于视图的视图
--建立选修了1号课程且成绩在90分以上的学生的视图
CREATE VIEW IS_S2
AS SELECT Sno, Sname, Grade FROM IS_S1 WHERE Grade >= 90;
--带表达式的视图
--需要明确指定字段名
CREATE VIEW BT_S(Sno, Sname, Sbirth)
AS SELECT Sno, Sname, 2014-Sage FROM Student;
--分组视图
--将学生的学号和平均成绩建立视图
CREATE VIEW S_G(Sno, Gavg)
AS SELECT Sno, Avg(Grade) FROM SC GROUP BY Sno;
DROP VIEW <视图名> [CASCADE];
查询视图
更新视图
--不允许更新
UPDATE S_G SET Gavg = 90 WHERE Sno = '2012134';
UPDATE IS_Student SET Sname = '哈哈' WHERE Sno = '201215121';
--转换后
UPDATE Student SET Sname = '哈哈' WHERE Sno = '201215121' AND Sdept = 'IS';
INSERT INTO IS_Student VALUES('2019211','JOHN GOOD ENOUGH',20);
--转换后
INSERT INTO Student(Sno, Sname, Sage, Sdept) VALUES('2019211','JOHN GOOD ENOUGH',20,'IS');
--删除记录
DELETE FROM IS_Student WHERE Sno = '2012111';
--转换后
DELETE FROM Student WHERE Sno = '2012111' AND Sdept = 'IS';
视图的作用