个人笔记:数据库 第三章 SQL

参考文献链接1(基本介绍)

参考文献链接2(复习例题)

参考资料3:中国大学MOOC——中国人民大学“数据库系统概论”

SQL语言种类 操作
DDL 数据定义语言 create(创建) drop(删除) alte(修改)
DQL 数据查询语言 select(查询)
DML 数据操纵语言 insert(插入) update(更新) delete(删除)
DCL 数据控制语言 grant(授予) revoke(吊销)

视图链接

目录:

    • SQL语言的分类
    • DDL数据定义语言
      • SQL server常用数据类型
      • 约束语句
      • 1.基本表的定义删除与修改:
      • 2.索引的定义删除与修改:
      • 3. 库的定义删除与修改:
    • DQL数据查询语言
      • 1.查询全部列
      • 2.表达式使用了函数的查询
      • 3.使用列别名改变查询结果的列标题
      • 4.消除取值重复的行
      • 5.条件查询
        • 1.条件查询:
        • 2.多重条件查询:
        • 4.聚集函数:
        • 5.分组查询:group by 子句
        • 6.连接查询
          • 1.等值与非等值连接查询
          • 2.自身连接
          • 3.外连接
          • 4.多表连接
      • 6.数据查询(嵌套查询)
        • 1.带有IN谓词的子查询
        • 2.带有比较运算符的子查询
        • 3.带有ANY(SOME)或ALL谓词的子查询
        • 4.带有EXISTS谓词的子查询
      • 7.集合查询
        • 并操作UNION
        • 交操作INTERSECT
        • 差操作EXCEPT
    • DML 数据操纵语言
    • DCL 数据控制语言

SQL语言的分类

SQL语言种类 操作
DDL 数据定义语言 create(创建) drop(删除) alte(修改)
DQL 数据查询语言 select(查询)
DML 数据操纵语言 insert(插入) update(更新) delete(删除)
DCL 数据控制语言 grant(授予) revoke(吊销)

DDL数据定义语言

SQL server常用数据类型

  • 整数类型:
  1. BIGINT——8字节的整型
  2. INT——4字节的整型
  3. SMALLINT——2字节的整型 范围从-32768到32767
  4. TINYINT——1字节的整型 范围从-255到255
  5. BIT——1位的整型 只能表示0或1,用来表示真假逻辑关系(FALSE/TRUE)
  • 浮点型:
  1. FLOAT(n)——可选精度的浮点数,精度至少为n位数字
  2. REAL——4字节的浮点数型
  • 数字数据类型:

p(精度):小数点两边的总位数
s(小数位数):小数点右边的位数

  1. DECIMAL(p,s)
  2. NUMERIC(p,s)
  • 日期/时间类型:
  1. date-----------日期型
  2. DATETIME——存储从1753年1月1日至9999年12月31日的日期(每个数值要求8个字节的存储空间)
  3. SMALLDATETIME——存储从1900年1月1日至2079年6月6日的日期(每个数值要求 4 个字节的存储空间)
  • 字符数据类型
  1. CHAR(n) ——n个字节,具体值由n决定
  2. VARCHAR(n):最大为n个字节

约束语句

  • not null 非空约束
  • unique 唯一约束
    一个表只能有一个唯一约束
  • primary key 主键约束
    [constraint <约束名>] primary key (列名[{,列名}])
  • foreign key 外键约束
    [constraint <约束名>] foreign key references <主表名> (<列名>[{,列名}])
  • check 检查约束
    [constraint <约束名>] check (<条件>)
    一个表可以定义多个check约束,但是每个字段只能定义一个check约束
  • default 默认初始值
    如果没有输入,就是该默认值,不为NULL

1.基本表的定义删除与修改:

  1. create:
create table <表名1> (<字段1 数据类型 约束>,<字段2 数据类型 约束>,primary key(字段1,字段2) )

eg:

create table Room(
roomNo char(10) primary key,
hotelNo char(10) default0000000000,
type char(10) not null,
price char(10) not null check(price>=100),
foreign key(hotelNo) references Hotel(hotelNo)
);

//若primary key是由多个属性组成则
//表级约束性条件加上 primary key(A,B),
  1. drop:
drop table <表名>

eg:

ALTER TABLE Course DROP CONSTRAINT 自定义的约束名
//删除属性的某约束条件,约束名是用户自定义的
  1. alte:
//add语句 添加 列
alter table <表名> add <列名 数据类型 约束>

//alter语句 修改约束条件或数据类型
alter table <表名> alter column <列名> <数据类型> <约束>

eg:

alter table Course add unique (Cname)//未自定义约束条件约束名
ALTER TABLE Course ADD constraints aaa UNIQUE(Cname)//自定义约束条件约束名

alter table Student alter column Sage int

2.索引的定义删除与修改:

  • 索引的作用
  1. 在日常生活中我们会经常遇到索引,例如图书目录、词典索引等。
  2. 借助索引,人们会很快地找到需要的东西。
  3. 索引是数据库随机检索的常用手段,它实际上就是记录的关键字与其相应地址的对应表。
  4. 例如,当我们要在本书中查找有关“SQL查询”的内容时,应该先通过目录找到“SQL查询”所对应的页码,然后从该页码中找出所要的信息。这种方法比直接翻阅书的内容要快。
  5. 如果把数据库表比作一本书,则表的索引就如书的目录一样,通过索引可大大提高查询速度。
  6. 此外,在SQL SERVER中,行的唯一性也是通过建立唯一索引来维护的。
  • 索引的作用可归纳为:
  1. 加快查询速度;
  2. 保证行的唯一性。

  1. create
CREATE INDEX [UNIQUE / CLUSTER] 索引名 ON 表名(
列名 [次序] 
[,列名 [次序] ]
)

eg:

CREATE UNIQUE INDEX  Stusno ON Student(Sno)CREATE UNIQUE INDEX  Coucno ON Course(Cno)CREATE UNIQUE INDEX  SCno ON SC(Sno ASC,Cno DESC)
  1. drop
DROP INDEX 数据表名.索引

eg:

Drop index S_idx

3. 库的定义删除与修改:

  1. create:
create database 数据库名称
on(
    name=数据文件逻辑名称,
    filename='路径+数据文件名',
    size=数据文件初始大小,
    maxsize=数据文件的最大容量,
    filegrowth=数据文件自动增长量,
)
[log on(
    name = 日志文件逻辑名称,
    filename='路径+日志文件名',
    size=数据文件初始大小,
    maxsize=数据文件的最大容量,
    filegrowth=数据文件自动增长量,
)]
  1. drop:
ADD FILE :向数据库添加数据文件
alter database 数据库名称
add file(
    name=数据文件逻辑名称,
    filename='路径+数据文件名',
    size=数据文件初始大小,
    maxsize=数据文件的最大容量,
    filegrowth=数据文件自动增长量,
)
ADD LOG FILE :向数据库添加日志文件
REMOVE FILE:从数据库删除逻辑文件,并删除物理文件。无法删除文件组不为空的文件。
MODIFY FILE:指定要修改的文件
  1. alte:
drop database 数据库名称

DQL数据查询语言

SELECT [ALL|DISTINCT] <目标列表达式>[,<目标列表达式>] ...
FROM <表名或视图名>[,<表名或视图名> ]...|(SELECT 语句) [AS]<别名>
[ WHERE <条件表达式> ]
[ GROUP BY <列名1> 
[ HAVING <条件表达式> ] ] 
[ ORDER BY <列名2> [ ASC|DESC ] ];
/*
SELECT子句:指定要显示的属性列
FROM子句:指定查询对象(基本表或视图) 
WHERE子句:指定查询条件
GROUP BY子句:对查询结果按指定列的值分组,该属性列值相 等的元组为一个组。通常会在每组中作用聚集函数。
HAVING短语:只有满足指定条件的组才予以输出
ORDER BY子句:对查询结果表按指定列值的升序或降序排序
 */

1.查询全部列

//投影该表的所有信息:
select * from 表名
// * 代指原表中的所有列 且顺序都和原表一致

eg:

//查询全体学生的详细记录 
SELECT Sno,Sname,Ssex,Sage,Sdept FROM Student;
//或
SELECT * FROM Student;

2.表达式使用了函数的查询

表达式使用了函数的查询

//SELECT 子句的 <目标列表达式> 不仅可以为表中的 属性列,也可以是 表达式 或 函数

eg: lower() 小写函数 ;date() 日期函数 ;year()取年份

//查全体学生的姓名及其出生年份,Sname是隐含条件列
SELECT Sname,2016-Sage FROM Student;
//or
select Sname,year(data())-Sage from Student;

//查询全体学生的姓名、出生年份和所在的院系,要 求用小写字母表示系名。
SELECT Sname,'Year of Birth: ',2014-Sage,LOWER(Sdept) FROM Student;
//输出结果:
Sname  'Year of Birth:' 2014-Sage  LOWER(Sdept)
李勇		Year of Birth:	 1944		 cs
刘晨 	Year of Birth:	 1955		 ma

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

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

select <列名> 空格 <自定义别名>
[,<列名> 空格 <自定义别名>,]
from <表名>;
//或
select <列名> as <自定义别名>
[,<列名> as <自定义别名>,]
from <表名>;

eg:

SELECT Sname NAME,
'Year of Birth:' BIRTH,
2014-Sage BIRTHDAY,
LOWER(Sdept) DEPARTMENT 
FROM Student;
//输出结果:
NAME 	BIRTH 			BIRTHDAY 	DEPARTMENT
李勇 	Year of Birth:	1944		cs
刘晨		Year of Birth:	1955		ma

4.消除取值重复的行

省略重复的行

//如果没有指定DISTINCT关键词,则缺省为ALL ,ALL即为不取消重复的元组
SELECT DISTINCT <目标列表达式>
[,<目标列表达式>] FROM <表名或视图名>;

eg:

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

//默认 ALL 时
SELECT Sno FROM SC;
//结果为:
	Sno 
 201215121 
 201215121 
 201215121 
 201215122 
 201215122
// DISTINCT 时
SELECT DISTINCT Sno FROM SC;
//结果为:
 	Sno 
 201215121 
 201215122

5.条件查询

1.条件查询:

where + 对元组某一属性进行限制的条件

与直接在select F(列名) 的区别在于,where 对元组的某一属性进行的限制可以不对限制条件的属性进行输出,而select后的所有属性都要有输出

select <列名,[列名2]> from 表名 where 条件

个人笔记:数据库 第三章 SQL_第1张图片

  1. 比较大小:=, >, <, >=, <=, !=, <>, !>, !<; NOT+上述比较运算符
//查询考试成绩有不及格的学生的学号
SELECT DISTINCT Sno
FROM SC
WHERE Grade<60;
  1. 确定范围:BETWEEN … AND … (a ≤ x ≤ b),NOT BETWEEN … AND …
//查询年龄不在20~23岁之间的学生姓名、系别和年龄
SELECT Sname, Sdept, Sage
FROM Student
WHERE Sage NOT BETWEEN 20 AND 23;
  1. 确定集合:IN <值表>, NOT IN <值表>
//查询既不是计算机科学系、数学系,也不是信息系 的学生的姓名和性别。
SELECT Sname, Ssex 
FROM Student
WHERE Sdept NOT IN ('IS','MA’,'CS' );
  1. 字符匹配:[NOT] LIKE ‘<匹配串>’ [ESCAPE ‘ <换 码字符>’]
  • <匹配串>可以是一个完整的字符串,也可以含有通配符%和 _

  • % (百分号) 代表任意长度(长度可以为0)的字符串 例如a%b表示以a开头,以b结尾的任意长度的字符串

  • _ (下横线) 代表任意单个字符。 例如a_b表示以a开头,以b结尾的长度为3的任意字符串

  • 如需输出%或_则可以使用 / 或者[]进行 转意符
    用/转义: 每一个条件后面需要加 escape ‘/’
    用[]转义:直接在写条件时候在[]输入原本意义的字符

//1.匹配串为固定字符串:
//查询学号为201215121的学生的详细情况
select *
from SC
where Sno like201215121;

//2.匹配串为含通配符的字符串:
//查询所有姓刘学生的姓名、学号和性别
SELECT Sname, Sno, Ssex
FROM Student
WHERE Sname LIKE ‘刘%;

//3.匹配串为含通配符的字符串:
//查询姓"欧阳"且全名为三个汉字的学生的姓名
SELECT Sname
FROM Student
WHERE Sname LIKE ‘欧阳__’;

//4.使用换码字符将通配符转义为普通字符:
//查询以"DB_"开头,且倒数第3个字符为 i的课程的详细情况。
SELECT *
FROM Course
WHERE Cname LIKE 'DB/_%i_ _' ESCAPE '/' ;
//ESCAPE '/' 表示“ /” 为换码字符

SELECT *
FROM Course
WHERE Cname LIKE 'DB[_]%i_ _';
  1. IS NULL 或 IS NOT NULL (“IS” 不能用 “=” 代替)
//某些学生选修课程后没有参加考试,所以有选课记 录,但没 有考试成绩。
//查询缺少成绩的学生的学号和相应的课程号
SELECT Sno,Cno 
FROM SC
WHERE Grade IS NULL

2.多重条件查询:

  • 逻辑运算符:AND 和 OR来连接多个查询条件
  1. AND的优先级高于OR
  2. 可以用括号改变优先级
//查询计算机系年龄在20岁以下的学生姓名。
SELECT Sname
FROM Student
WHERE Sdept= 'CS' AND Sage<20;
  • ORDER BY子句

注意是order by 不是 group by
对结果进行排序,要写在最后

可以按一个或多个属性列排序
升序:ASC;(default为ASC)
降序:DESC;
对于空值,排序时显示的次序由具体系统实现来 决定

//查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
SELECT Sno, Grade 
FROM SC
WHERE Cno='3' 
ORDER BY Grade DESC;

//查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
SELECT *
FROM Student
ORDER BY Sdept ASC, Sage DESC;

4.聚集函数:

  • 常用库函数
    avg平均值, sum总和, max最大, min最小, count计数
  1. 统计元组个数:
    COUNT(*)
  2. 统计一列中值的个数:
    COUNT([DISTINCT|ALL] <列名>)
  3. 计算一列值的总和(此列必须为数值型)
    SUM([DISTINCT|ALL] <列名>)
  4. 计算一列值的平均值(此列必须为数值型)
    AVG([DISTINCT|ALL] <列名>)
  5. 求一列中的最大值和最小值
    MAX([DISTINCT|ALL] <列名>)
    MIN([DISTINCT|ALL] <列名>)
//查询学生总人数 
SELECT COUNT(*)
FROM Student;

//查询选修了课程的学生人数
SELECT COUNT(DISTINCT Sno)
FROM SC;

//计算1号课程的学生平均成绩
SELECT AVG(Grade) 
FROM SC
WHERE Cno= ' 1 ';

//查询选修1号课程的学生最高分数
SELECT MAX(Grade)
FROM SC 
WHERE Cno='1';

//查询学生201215012选修课程的总学分数
SELECT SUM(Ccredit)
FROM SC,Course
WHERE Sno='201215012' AND SC.Cno=Course.Cno;

5.分组查询:group by 子句

注意是group by 不是order by
细化聚集函数的作用对象:

  • 如果未对查询结果分组,聚集函数将作用于整个查询结果
  • 对查询结果分组后,聚集函数将分别作用于每个组
  • 按指定的一列或多列值分组,值相等的为一组
  • WHERE子句中是不能用聚集函数作为条件表达式(要用having)

HAVING短语与WHERE子句的区别:

  • 作用对象不同
  • WHERE子句作用于基表或视图,从中选择满足条件的元组
  • HAVING短语作用于组,从中选择满足条件的组。
SELECT	目标列表达式,   集函数(列名)
FROM		表名
[WHERE	条件表达式]
[GROUP BY	分组条件表达式]
[ORDER BY	列名];

个人笔记:数据库 第三章 SQL_第2张图片

//求各个课程号及相应的选课人数
SELECT Cno,COUNT(Sno) 
FROM SC
GROUP BY Cno; 
//查询结果可为:
Cno COUNT(Sno) 
1 	22
2 	34 
3 	44 
4 	33 
5 	48

//查询选修了3门以上课程的学生学号。
SELECT Sno
FROM SC
GROUP BY Sno 
HAVING COUNT(*) >3;

6.连接查询

join
(1)inner join(内连接)
(2)left (outer) join 左(外)连接 --以左边的表为基准(右边缺乏数据为null)
(3)right (outer) join 右(外)连接 --以右边的表为基准(左边缺乏数据为null)
(4)full (outer) join 完整(外)连接(缺乏数据为null)

1.等值与非等值连接查询
  • 等值连接:连接运算符为 “=”
//查询每个学生及其选修课程的情况 
SELECT Student.*, SC.*
FROM Student, SC
WHERE Student.Sno = SC.Sno;

//结果:
Student.Sno Sname Ssex Sage Sdept 	 SC.Sno 		Cno Grade
201215121	李勇		男	20	CS 		201215121		1	92 
201215121	李勇		男	20	CS 		201215121		2	85 
201215121	李勇		男	20	CS 		201215121		3	88 
201215122	刘晨		女	19	CS     	201215122		2	90 
201215122	刘晨		女	19	CS     	201215122		3	80
  • 自然连接:采用在SELECT中去掉重复字段的方式实施

没有自然连接的运算符,故直接输入自然连接后的列名称

//自然连接
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade 
FROM Student,SC
WHERE Student.Sno = SC.Sno;
  1. 嵌套循环法(NESTED-LOOP)

    • 首先在表1中找到第一个元组,然后从头开始扫描表2,逐一查找满足 连接件的元组,找到后就将表1中的第一个元组与该元组拼接起来, 形成结果表中一个元组。
    • 表2全部查找完后,再找表1中第二个元组,然后再从头开始扫描表2 ,逐一查找满足连接条件的元组,找到后就将表1中的第二个元组与 该元组拼接起来,形成结果表中一个元组。
    • 重复上述操作,直到表1中的全部元组都处理完毕
  2. 排序合并法(SORT-MERGE)

    • 常用于等值连接
    • 首先按连接属性对表1和表2排序。
    • 设置指针,分别指向表1和表2的第一个元组。如果这两个元组满足 连接条件,则进行元组拼接(如果有多个连续元组满足连接条件, 则需要一一拼接),并将两指针分别后移一个原则。否则,将具有 较小值的指针后移一个元组
    • 重复上述操作,直到表1或表2中的全部元组都处理完毕为止
  3. 索引连接(INDEX-JOIN)

    • 对表2按连接字段建立索引
    • 对表1中的每个元组,依次根据其连接字段值查询表2的索引,从 中找到满足条件的元组,找到后就将表1中的第一个元组与该元 组拼接起来,形成结果表中一个元组
    • (该方法可以视作嵌套循环法的一个变种)
//查询选修2号课程且成绩在90以上的所有学生的姓名和学号
SELECT Student.Sno, Sname 
FROM Student, SC
WHERE Student.Sno=SC.Sno //连接谓词
AND SC.Cno=' 2 ' AND SC.Grade>90;//选择谓词
2.自身连接
  • 自身连接:一个表与其自己进行连接,是一种特殊的连接
  • 需要给表起别名以示区别
  • 由于所有属性名都是同名属性,因此必须使用别名前缀
//查询每一门课的直接先修课的名称
SELECT FIRST.Cname,SECOND.Cname
FROM Course FIRST, Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;

//表
课程号Cno	课程名Cname	先行课Cpno	学分Ccredit
1			数据库		5			4
2			数学						2
3			信息系统		1			4
4			操作系统		6			3
5			数据结构		7			4
6			数据处理导论				2	
7			C语言		6			4

//结果:
First.Cname		Second.Cname
  数据库		 	 数据结构
  信息系统		 数据库
  操作系统		 数据结构
  数据结构		 C语言
  C语言			 数据处理导论
3.外连接

(1)left (out) join 左(外)连接 --以左边的表为基准(右边缺乏数据为null)
(2)right (out) join 右(外)连接 --以右边的表为基准(左边缺乏数据为null)
(3)full (out) join 完整(外)连接(缺乏数据为null)

  • 外连接与普通连接的区别
    1. 普通连接操作只输出满足连接条件的元组
    2. 外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出
    3. 左外连接: 列出左边关系中所有的元组
    4. 右外连接: 列出右边关系中所有的元组
//查询每个学生及其选修课程的情况
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;

//结果:
Student.Sno Sname Ssex Sage Sdept  Cno 		Grade
201215121 	李勇 	男 	20 	CS		1 		92
201215121 	李勇 	男 	20 	CS     	2 		85
201215121 	李勇 	男 	20 	CS      3 		88
201215122 	刘晨 	女 	19	CS     	2 		90
201215122	刘晨		女	19	CS		3 		80
201215123	王敏		女	18 	MA		NULL 	NULL
201215125	张力		男	19	IS		NULL 	NULL
4.多表连接

多表连接:两个以上的表进行连接

//查询每个学生的学号、姓名、选修的课程名及成绩 
SELECT Student.Sno, Sname, Cname, Grade
FROM Student, SC, Course //多表连接
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno;

6.数据查询(嵌套查询)

  • 一个SELECT-FROM-WHERE语句称为一个查询块
  • 将一个查询块嵌套在另一个查询块的WHERE子句 或HAVING短语的条件中的查询称为嵌套查询
  • 子查询的限制:Order By 子句不可以出现在嵌套块中
  • 上层的查询块称为外层查询或父查询
  • 下层查询块称为内层查询或子查询
  • SQL语言允许多层嵌套查询
SELECT Sname //外层查询  父查询
FROM Student
WHERE Sno IN
(SELECT Sno //内层查询  子查询
FROM SC
WHERE Cno= ' 2 ');
  1. 不相关子查询
  • 不相关子查询:子查询的查询条件不依赖于父查询
  • 由里向外 逐层处理。即每个子查询在上一级查询处理 之前求解,子查询的结果用于建立其父查询的查找条 件。
  1. 相关子查询
    相关子查询:子查询的查询条件依赖于父查询
  • 首先取外层查询中表的第一个元组,根据它与内层查 询相关的属性值处理内层查询,若WHERE子句返回值 为真,则取此元组放入结果表
  • 然后再取外层表的下一个元组
  • 重复这一过程,直至外层表全部检查完为止

1.带有IN谓词的子查询

eg1:

  • 不相关子查询
//查询与“刘晨”在同一个系学习的学生。此查询要求可以分步来完成

//1 确定“刘晨”所在系名
SELECT Sdept
FROM Student 
WHERE Sname= ' 刘晨 ';
//结果为: CS

//2 查找所有在CS系学习的学生。
SELECT Sno, Sname, Sdept
FROM Student
WHERE Sdept= ' CS ';
//结果为:
Sno 		Sname	Sdept
201215121 	李勇 	CS 
201215122	刘晨		CS

//将第一步查询嵌入到第二步查询的条件中
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 = '刘晨';

eg2:

//查询选修了课程名为“信息系统”的学生学号和姓名
SELECT Sno,Sname    //3 最后在Student关系中 取出Sno和Sname
FROM Student 
WHERE Sno IN
(SELECT Sno         //2 然后在SC关系中找出选 修了3号课程的学生学号
FROM SC 
WHERE Cno IN
(SELECT Cno         //1 首先在Course关系中找出 “信息系统”的课程号,为3号
FROM Course
WHERE Cname= '信息系统'));
//用连接查询实现: 
SELECT Sno,Sname
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno AND Course.Cname='信息系统';

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

当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >)
eg1:

//查询与“刘晨”在同一个系学习的学生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept = /*由于一个学生只可能在一个系学习 , 用=代替*/
(SELECT Sdept
FROM Student 
WHERE Sname= '刘晨');

eg2:

//找出每个学生超过他选修课程平均成绩的课程号。
SELECT Sno, Cno
FROM SC x    //相关子查询
WHERE Grade >=
(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno);

//可能的执行过程
//从外层查询中取出SC的一个元组x,将元组x的Sno值 (201215121) 传送给内层查询。 
SELECT AVG(Grade)
FROM SC y
WHERE y.Sno='201215121;

//执行内层查询,得到值88(近似值),用该值代替内层查询,得到外层查询:
SELECT Sno,Cno 
FROM SC x 
WHERE Grade >=88;
//执行该查询,得到结果: 
(201215121,1) 
(201215121,3)
//然后外层查询取出下一个元组重复做上述1至3 步骤,直到外层的SC元组全部处理完毕。
//结果为: 
(201215121,1)
(201215121,3) 
(201215122,2)

3.带有ANY(SOME)或ALL谓词的子查询

在谓词逻辑中,还有存在量词和全称量词的概念,在SQL中并没有对应的表达,统一采用“谓词” 来表达

 - 方法一:
引入ANY和ALL谓词,其对象为某个查 询结果,表示其中任意一个值或者全部值

 - 方法二:
引入EXIST谓词,其对象也是某个查询结 果,但表示这个查询结果是否为空,返回真值。

使用ANY或ALL谓词时必须同时使用比较运算
语义为:

   > ANY    大于子查询结果中的某个值 
   > ALL    大于子查询结果中的所有值
   < ANY    小于子查询结果中的某个值
   < ALL    小于子查询结果中的所有值
   >= ANY   大于等于子查询结果中的某个值
   >= ALL   大于等于子查询结果中的所有值
   <= ANY	小于等于子查询结果中的某个值 
   <= ALL	小于等于子查询结果中的所有值
   = ANY	等于子查询结果中的某个值
   = ALL	等于子查询结果中的所有值(无意义)
  !=(或<>)ANY 不等于子查询结果中的某个值
  !=(或<>)ALL 不等于子查询结果中的任何一个值
//ANY(或SOME),ALL谓词与聚集函数、IN谓词的等 价转换关系
	 =		<>!=		<		<=		>		>=
ANY	IN					<MAX	<=MAX	>MIN	>= MIN
ALL 		NOT IN		<MIN	<= MIN	>MAX	>= MAX

eg1:

//查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage < ANY 
(SELECT Sage
FROM Student
WHERE Sdept= ' CS ') 
AND Sdept <> ‘CS ' ; //父查询块中的条件

//结果:
Sname 	Sage 
王敏 	18 
张立 	19
//执行过程:
(1)首先处理子查询,找出CS系中所有学生的年龄,构成一个 集合(20,19)
(2)处理父查询,找所有不是CS系且年龄小于2019的学生
//用聚集函数实现
SELECT Sname,Sage 
FROM Student 
WHERE Sage <
(SELECT MAX(Sage) 
FROM Student 
WHERE Sdept= 'CS ')
AND Sdept <> ' CS ';

eg2:

//查询非计算机科学系中比计算机科学系所有学 生年龄都小的学生姓名及年龄。
//方法一:用ALL谓词 
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 ';

4.带有EXISTS谓词的子查询

EXISTS谓词

  • 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true” 或逻辑假值“false”。
    • 若内层查询结果非空,则外层的WHERE子句返回真值
    • 若内层查询结果为空,则外层的WHERE子句返回假值
  • 由EXISTS引出的子查询,其目标列表达式通常都用 * ,因为带
    EXISTS的子查询只返回真值或假值,给出列名无实际意义。

eg1:

//查询所有选修了1号课程的学生姓名。
//思路分析:
//1.本查询涉及Student和SC关系
//2.在Student中依次取每个元组的Sno值,用此值去检查SC表
//3.若SC中存在这样的元组,其Sno值等于此Student.Sno值, 并且其Cno= ‘1’,则取此Student.Sname送入结果表

SELECT Sname 
FROM Student 
WHERE EXISTS
(SELECT *
FROM SC
WHERE Sno=Student.Sno AND Cno= ' 1 ');

eg2:

//查询没有选修1号课程的学生姓名
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno = Student.Sno AND Cno='1');
  • 用EXISTS代替其他谓词
    ◼ 所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带 EXISTS谓词的子查询等价替换
  • 用EXISTS/NOT EXISTS实现全称量词(难点)
  • 用EXISTS实现逻辑蕴含
    ◼ 可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
    在这里插入图片描述

eg1:

//查询与“刘晨”在同一个系学习的学生。可以用带EXISTS谓词的相关子查询替换:
SELECT Sno,Sname,Sdept 
FROM Student S1
WHERE EXISTS 
(SELECT *
FROM Student S2
WHERE S2.Sdept = S1.Sdept AND S2.Sname = '刘晨');

eg2:

//查询选修了全部课程的学生姓名。 
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实现逻辑蕴涵(难点)

  • SQL语言中没有蕴涵(Implication)逻辑运算
  • 可以利用谓词演算将逻辑蕴涵谓词等价转换为:
    p → q ≡ ¬ p∨q

eg:
查询至少选修了学生201215122选修的全部课程的 学生号码。

  • 解题思路:
    用逻辑蕴涵表达该查询:

    • 用P表示谓词 “学生201215122选修了课程y”

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

    则上述查询为: (y) p → q对(所有的课程y,只要201215122学生选修了课程y,则x也选修了y)

  • 等价变换:
    个人笔记:数据库 第三章 SQL_第3张图片

  • 变换后语义:
    不存在这样的课程y,学生201215122选修了 y,而学生x没有选。

SELECT DISTINCT SCX.Sno 
FROM SC SCX
WHERE NOT EXISTS
(SELECT *    // P & Not(Q)
FROM SC SCY
WHERE SCY.Sno = ' 201215122 ' AND
NOT EXISTS 
(SELECT *
FROM SC SCZ
WHERE SCZ.Sno=SCX.Sno AND SCZ.Cno=SCY.Cno));

7.集合查询

  • 集合操作的种类
    - 并操作UNION
    - 交操作INTERSECT
    - 差操作EXCEPT

参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同

并操作UNION

eg1:

//查询计算机科学系的学生及年龄不大于19岁的学生 
SELECT *
FROM Student 
WHERE Sdept= 'CS' 
UNION
SELECT *
FROM Student 
WHERE Sage<=19;
//UNION:将多个查询结果合并起来时,系统自动去掉重复元组
//UNION ALL:将多个查询结果合并起来时,保留重复元素

eg2:

//查询选修了课程1或者选修了课程2的学生。
SELECT Sno 
FROM SC 
WHERE Cno=' 1 ' 
UNION
SELECT Sno 
FROM SC
WHERE Cno= ' 2 ';

交操作INTERSECT

eg1:

//查询计算机科学系的学生与年龄不大于19岁的学生的交集。
SELECT *
FROM Student 
WHERE Sdept='CS' 
INTERSECT 
SELECT *
FROM Student 
WHERE Sage<=19
//实际上就是查询计算机科学系中年龄不大 于19岁的学生。
SELECT *
FROM Student
WHERE Sdept= 'CS' AND Sage<=19;

eg2:

//查询既选修了课程1又选修了课程2的学生。
SELECT Sno 
FROM SC 
WHERE Cno=' 1 ' 
INTERSECT 
SELECT Sno 
FROM SC 
WHERE Cno='2 ';
//也可以表示为:
SELECT Sno
FROM SC
WHERE Cno=' 1 ' AND Sno IN
(SELECT Sno FROM SC
WHERE Cno=' 2 ');

差操作EXCEPT

eg1:

//查询计算机科学系的学生与年龄不大于19岁的 学生的差集。
SELECT *
FROM Student 
WHERE Sdept='CS' 
EXCEPT
SELECT *
FROM Student 
WHERE Sage <=19;
//实际上是查询计算机科学系中年龄大于19岁的学生
SELECT *
FROM Student
WHERE Sdept= 'CS' AND Sage>19;

DML 数据操纵语言

  1. 插:
insert into <表名> [列名,[<列名>,<列名>]]

eg:

insert into Hotel values(‘H1035’,‘前进宾馆’,‘长春’);
  1. 删:
delete from 表名 where 条件

eg:

delete from Booking where dateTo=20171202);
  1. 改:
update 表名 set 列名=where 条件

eg:

update Room set type = ‘单人间’
where roomNo =369and hotelNo in
(select hotelNo from Hotel where hotelName = ‘长春宾馆’)

DCL 数据控制语言

你可能感兴趣的:(DataBase)