文章目录
❖掌握
⬧ CREATE DATABASE
CREATE SCHEMA
⬧ CREATE TABLE
CREATE INDEX
❖了解
⬧ SQL语言的历史、特点
❖重点
⬧ 数据库、模式、表、索引的创建、删除
❖难点
⬧ 模式
集成管理系统
第一节 SQL概述
❖ 1.1 SQL
⬧ SQL语言原名SEQUEL(读作[si:kwl]),是一个通用的、功能极强的关系数据库语言。
同时也是一种介于关系代数与关系演算之间的结构化查询语言(Structured Query Language),
❖最早的SQL原型由IBM的研究人员在20世纪70年代开发的
❖20世纪80年代早期SQL开始成为国际标准的数据库语言
其功能包括数据定义、数据查询、数据操纵和数据控制
定义: create drop alter 创建,删除(全表),修改
查询: select 查询
操纵/更新: insert delete update 增加,删除(仅数据),改数据
控制: grant revoke 授权、回收
为什么学习SQL
⬧ SQL已经成为关系数据库的查询标准
⬧ SQL也是现在和将来DBMS的标准
⬧ SQL促进了分布式数据库和客户/服务器数据库的开发
SQL的特点
- ⬧ 综合统一
- ⬧ 高度非过程化
- ⬧ 面向集合的操作方式
- ⬧ 两种使用方式,统一的语法结构
- ⬧ 简洁易学
第二节 学生-课程数据库基本信息
S-T是个容器,里面有很多表
Student 表
Course 表
SC 表
第三节 数据定义
数据库的结构
数据库 --> 架构 --> 表,从左到右都是一对多的关系。
有架构的话使用表时需要带上架构名字。
可以不用架构,但是会默认把表创建到默认的dbo架构里面
SQL的数据定义功能
模式定义
表定义
视图定义
索引定义
3.1 数据库的创建和修改
# 创建数据库
create database 数据库名称;
举例: create database test1;
# 使用数据库(切换当前数据库)
use 数据库名称;
举例: use test1;
# 删除数据库
drop database 数据库名字;
举例: drop database text1;
3.2 模式的定义和删除
模式是一个独立于数据库用户的非重复命名空间,
在这个空间中可以定义该模式包含的数据库对象,例如基本表、视图、索引等。
您可以将模式视为数据库对象的容器
一个数据库可以有多个模式,模式隶属于数据库
有架构的话使用表时需要带上架构名字。 xxx.sss;
可以不用架构,但是会默认把表创建到默认的 dbo 架构里面
.
.
–数据库中创建模式(容器) --位置:student -> 安全性 -> 架构
–create schema s_t;
--删除模式 --可能会报错,不用理会
--drop schema s_t;
# 创建模式
create schema<模式名> AUTHORIZATION <用户名> [<表定义> |<视图定义>|<授权定义>]
⬧ 如果没有指定模式名,则模式名隐含为用户名
⬧ 权限:使用该命令,用户必须具有DBA权限,或获得了DBA授权create schema的权限
❖例: create schema Test authorization zhang,
创建了一个模式,模式隶属于zhang;
# 删除模式
drop schema<模式名> <CASCADE | RESTRICT>
⬧ CASCADE(级联)
➢删除模式的同时把该模式中所有的数据库对象全部删除
⬧ RESTRICT(限制)
➢如果该模式中定义了下属的数据库对象(如表、视图等),则拒绝该删除语句的执行
➢当该模式中没有任何下属的对象时 才能执行
创建数据库
create database student;
使用数据库(切换当前数据库)
use student;
数据库中创建模式(容器) --位置:student -> 安全性 -> 架构
create schema s_t;
删除模式 --可能会报错,不用理会
drop schema s_t;
删除数据库
drop database student;
3.3 表的定义、修改和删除
❖创建表时,需要搞清楚的问题
⬧ 表名是什么?
⬧ 此表包括那些列?
⬧ 各列名是什么?
⬧ 各列的长度和数据类型是什么?
⬧ 列是否允许取空值?
⬧ 列是否取唯一值?
⬧ 哪些列组成表的主键?
⬧ 外键及被参照的关系是什么?
❖数据类型
⬧ SQL中域的概念用数据类型来实现
⬧ 定义列时需要指明其数据类型及长度
⬧ 选用哪种数据类型
➢取值范围
➢要做哪些运算
定义基本表
create table <表名>
<列名> <数据类型> [ <列级完整性约束条件> ]
[,<列名> <数据类型> [ <列级完整性约束条件>] ] …
[,<表级完整性约束条件> ] );
⬧ <列级完整性约束条件>:涉及相应属性列的完整性约束条件
⬧ <表级完整性约束条件>:涉及一个或多个属性列的完整性约束条件
create table student--建表,名字为Student,后面跟括号
(
sno char(9) primary key,--列名sno,类型为char,限制长度为9,
--primaty key代表他为主键,最后面用逗号做分隔符。
/*
--或者这样写
--sno char(9),
--表格最后加上primaty key(sno)*/
sname char(10) not null,--不许为空值,若为unique的话表示不允许重复
ssex char(2),
sage int, --int宽度是固定的4
sdept varchar(10) --最后一个不能有逗号
);
--------------------------------------------------------
create table course
(
cno char(4) primary key,
cname char(10) unique,--nuique不允许重复
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) references student(sno),
foreign key(cno) references course(cno)
)
修改基本表
ALTER TABLE <表名> (必须有)
[ ADD [COLUMN]<新列名> <数据类型> [ 完整性约束 ] ] SQL不需要column关键字
[ ADD <表级完整性约束>]
[ DROP [COLUMN]<列名>[CASCADE|RESTRICT] ] 删除必须要column关键字
[ DROP CONSTRAINT<完整性约束名[CASCADE|RESTRICT] ]
[ ALTER COLUMN <列名> <数据类型> ];
⬧ <表名>:要修改的基本表
⬧ ADD子句:增加新列和新的完整性约束条件
⬧ DROP子句:删除指定的完整性约束条件
⬧ ALTER COLUMN子句:用于修改列名和数据类型
例4] 向Student表增加“入学时间”列,其数据类型为日期型。
ALTER TABLE Student ADD S_entrance DATE;
不论基本表中原来是否已有数据,新增加的列一律为空值。
[例5] 将年龄的数据类型由字符型(假设原来的数据类型是字符型)改为整数。
ALTER TABLE Student ALTER COLUMN Sage INT;
[例6] 增加课程名称必须取唯一值的约束条件。
ALTER TABLE Course ADD UNIQUE(Cname);
修改基本表
alter table sc
增加列
alter table sc
add list char(9); --add
删除列
alter table sc
drop column list --drop column必须有
更改数据类型
alter table sc
alter column grade char(12) --alter column
增加约束性条件
alter table Student
add unique(sname) --add unique 增加唯一性约束
为cname加非空属性 用修改的方法,因为 not null是两个单词
alter table course
alter column cname char(20) not null --alter column
删除基本表
DROP TABLE <表名>[RESTRICT| CASCADE];
❖RESTRICT:删除表是有限制的
⬧ 欲删除的基本表不能被其他表的约束所引用
⬧ 如果存在依赖该表的对象,则此表不能被删除
❖CASCADE:删除该表没有限制 (SQL中不好用)
⬧ 在删除基本表的同时,相关的依赖对象,视图也被一起删除
# 常用完整性约束
⬧ 主码约束: PRIMARY KEY 不可以空值
⬧ 唯一性约束:UNIQUE 可以空值
⬧ 非空值约束:NOT NULL
⬧ 参照完整性约束: FOREIGN KEY
3.4 索引的建立和删除
建立索引是加快查询速度的有效手段
⬧ 在一个基本表上最多只能建立一个聚簇索引
⬧ 聚簇索引的用途:对于某些类型的查询,可以提高查询效率
⬧ 聚簇索引的适用范围
➢ 很少对基表进行增删操作
➢ 很少对其中的变长列进行修改操作
聚簇索引是按照实际物理地址排序的,所以只有一个。
聚簇索引检索快,但是不适于频繁增删改的数据库。
建立索引
⬧ DBA或表的属主(即建立表的人)根据需要建立
⬧ 有些DBMS自动建立以下列上的索引
➢ PRIMARY KEY
➢ UNIQUE
.
CREATE [UNIQUE] [CLUSTER] INDEX <索引名> ON<表名>(<列名>[<次序>][,<列名>[<次序>] ]…);
⬧ 用<表名>指定要建索引的基本表名字
⬧ 索引可以建立在该表的一列或多列上,各列名之间用逗号分隔
⬧ 用<次序>指定索引值的排列次序,
(不写的话默认时升序索引,是普通索引,不是上面两个中的)
升序:ASC,
降序:DESC。
⬧ UNIQUE表明此索引的每一个索引值只对应唯一的数据记录
⬧ CLUSTER表示要建立的索引是聚簇索引
SQL用的时候 是 clustered,关键词末尾+ed;
[例8] 为学生-课程数据库中的Student,Course,SC三个表建立索引。其中
Student表按学号升序建唯一索引,Course表按课程号升序建唯一索引,SC
表按学号升序和课程号降序建唯一索引。
CREATE UNIQUE INDEX Stusno ON Student(Sno);
CREATE UNIQUE INDEX Coucno ON Course(Cno);
CREATE UNIQUE INDEX SCno ON SC(Sno ASC,Cno DESC);
唯一值索引(数值不可重复)
⬧ 对于已含重复值的属性列不能建UNIQUE索引
⬧ 对某个列建立UNIQUE索引后,插入新记录时DBMS会自动检查新记录在该
列上是否取了重复值。这相当于增加了一个UNIQUE约束
聚簇索引 . (一个表只能有一个)
⬧ 建立聚簇索引后,基表中数据也需要按指定的聚簇属性值的升序或降序存放。
也即聚簇索引的索引项顺序与表中记录的物理顺序一致
例如:
CREATE CLUSTER INDEX Stusname ON Student(Sname);
在Student表的Sname(姓名)列上建立一个聚簇索引,而
且Student表中的记录将按照Sname值的升序存放
维护索引
⬧ DBMS自动完成
使用索引
⬧ DBMS自动选择是否使用索引以及使用哪些索引
删除索引
DROP INDEX <索引名> 但是SQL用时候索引前需要加上表的名字
⬧ 删除索引时,系统会从数据字典中删去有关该索引的描述
[例9] 删除Student表的Stusname索引。
DROP INDEX Student.Stusname
--索引相当于一本书的目录,提升查找速度
--唯一值索引
create unique index stusno on Student (sno asc) ;
CREATE UNIQUE INDEX SCno ON SC(Sno ASC,Cno DESC)
--普通索引
create index scgrade on sc (grade desc);
--聚簇索引 (clustered )
create clustered index scgradel on sc(grade asc)
--删除普通与唯一值索引(表名.索引名)
drop index sc.scno;
drop index sc.scgrade;
drop index Student.stusno
每个表单创建时会自动生成一个有约束的聚簇索引,
想删除的话必须先把此索引与表单的关系删除
在表单右键进入设计,表格上右键选择索引键,选中关系删除即可
--删除表单自建的有约束的聚簇索引
drop index sc.[PK__Student__DDDF64462E645512]
第四节 数据查询
❖使用select语句:
⬧ 查询满足一定条件的元组
⬧ 查询某些属性的值
⬧ 使用表别名和列别名
⬧ 利用DISTINCT去掉查询结果中的重复行
⬧ 通过在WHERE子句中放入连接条件,进行多表连接查询
⬧ 利用GROUP BY进行分组统计
⬧ 利用ORDER对查询结果按要求排序
1. ❖ 查询语句概述
⬧ 基本语法
SELECT [ALL|DISTINCT]〈目标列表达式〉[,〈目标列表达式>] …
FROM 〈表名或视图名〉[,〈表名或视图名〉] …
[WHERE <条件表达式>] (条件选择)
[GROUP BY 〈列名〉[,〈列名〉]… (分组)
[HAVING <内部函数表达式>] ] (筛选)
[ORDER BY 〈列名〉 [ASC│DESC] [,〈列名〉[ASC│DESC]]…] (排序)
select后面的约束条件不写的话默认是all
⬧ 子句功能
⬧ SELECT子句与FROM子句是必选子句
⬧ SELECT ---- 列出查询的结果
⬧ FROM ---- 指明所访问的对象
⬧ WHERE ---- 指定查询的条件
⬧ GROUP BY ---- 将查询结果按指定字段的取值分组
⬧ HAVING ----筛选出满足指定条件的组
⬧ ORDER BY ---- 按指定的字段的值,以升序或降序排列查询结果
⬧ select语句的含义
根据WHERE子句中的条件表达式,从FROM子句中的基本表或视图中找出满足条件的元组
⬧ 按SELECT子句中的目标字段,选出元组中的分量形成结果表
⬧ GROUP BY子句将结果按字段分组,每个组产生结果表中的一个元组
⬧ 通常在每组中作用库函数,分组的附加条件用HAVING短语给出只有满足内部函数表达式的组才予输出
⬧ 如果有ORDER BY子句,则结果表要根据指定的字段按升序或降序排列
2. ❖ 单表查询
# ⬧ 投影查询
SELECT <目标列表达式> FROM <表名或视图名>
目标表达式可以是:属性名、算术表达式、字符串常量、函数等
例1] 查询全体学生的学号、姓名、所在系。
SELECT Sno,Sname,Sdept FROM Student;
[例2] 查询全体学生的详细记录。
SELECT * FROM Student;
[例3] 查询全体学生的姓名、出生年份。
SELECT Sname,2019 – Sage Birthday FROM Student;
[例4] 查询全体学生的人数。
SELECT count(Sname) FROM Student;
[例5] 在每个学生的姓名后面显示字符串 2017。
SELECT Sname,’2017' FROM student
❖取消重复行
⬧ 在SELECT子句中使用DISTINCT短语
--1. 投影查询
-- 查询特定列(所有学生的学号姓名与所在系)
select sno,sname,sdept from Student
-- 所有信息基本信息
select * from Student
-- 查询学生的学号,姓名与出生年份 (查询的新建列没有列名)
select sno,sname,2020-sage from Student;
-- 查询学生的学号,姓名与出生年份 (查询的新建有列名“别名”)
select sno,sname,2020-sage 出生年份 from Student;
-- 查询学生的学号,姓名与出生年份 (都换“别名”)
select sno 学号,sname 姓名,2020-sage 出生年份 from Student;
--查询每个人姓名,后面加“2018”
select sname,'2018'入学年份 from Student; --(注意有逗号)
--查询所有人姓名,出生日期,所在系(小写)
select sname,'year of birth' 生日,2020-sage 出生年份,lower(sdept) 所在系 from Student
-- 一共有多少学生
select count(sno) from Student --不管重复不重复,不统计空值(NULL)
select count(*) from Student --只统计有几行,不管里面的数值重复不重复
select distinct sno from sc --不重复查询
select count(distinct sno) from sc --不重复查询
select distinct cno,grade from sc --distinct作用域是后面的那个整体
# ⬧ 选择查询
--2. 选择查询 投影一般在选择之外
SELECT sname,sage FROM Student WHERE Sage < 20;
SELECT sname,sage FROM Student WHERE NOT Sage >= 20;
-- 查询性别为女的学号与姓名
select sno,sname from Student where ssex='女'
# 比较运算符
❖在WHERE子句的<比较条件>中使用比较运算符
⬧ =,>,<,>=,<=,!= 或 <>,!>,!<
⬧ 逻辑运算符NOT+比较运算符
[例7] 查询所有年龄在20岁以下的学生姓名及其年龄。
SELECT Sname,Sage FROM Student WHERE Sage < 20;
SELECT Sname,Sage FROM Student WHERE NOT Sage >= 20;
#范围 && 使用谓词
BETWEEN … AND …
NOT BETWEEN … AND …
[例8] 查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄。
SELECT Sname,Sdept,Sage FROM Student WHERE Sage BETWEEN 20 AND 23;
--查询年龄20-23的信息
select sname,sdept,sage from Student where sage between 18 and 20; --左必须小于右《=,》=
# 集合
IN <值表>,NOT IN <值表>
⬧ <值表>:用逗号分隔的一组取值
[例9] 查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
SELECT Sname,Ssex FROM Student WHERE Sdept IN ( 'IS','MA','CS' );
-- 查询以下几个系学生 --后面跟的是集合(当中任意一个都行)
select sno,sname,sdept from Student where sdept in ('CS','MA','IS')
# 字符串匹配
[NOT] LIKE ‘<匹配串>’ [ESCAPE ‘ <换码字符>’]
⬧ <匹配串>:指定匹配模板,可以是固定字符串或含通配符的字符串
⬧ 当匹配模板为固定字符串时,可以用 = 运算符取代 LIKE 谓词,用 != 或 < >运算符取代 NOT LIKE 谓词
⬧ 通配符
➢% (百分号) 代表任意长度(长度可以为0)的字符串
➢_ (下横线) 代表任意单个字符
⬧ 当用户要查询的字符串本身就含有 % 或 _ 时,要使用ESCAPE '<换码字符>' 短语对通配符进行转义
[例10] 查询所有姓刘学生的姓名、学号和性别。
SELECT Sname,Sno,Ssex FROM Student WHERE Sname LIKE ‘刘%’;
[例11] 查询姓“欧阳”且全名为三个汉字的学生的姓名。
一般一个汉字占用两个下划线。
SELECT Sname FROM Student WHERE Sname LIKE '欧阳_ _';
[例12] 查询DB_Design课程的课程号和学分。
SELECT Cno,Ccredit FROM Course WHERE Cname LIKE 'DB\_Design' ESCAPE '\'
[例13] 查询以“DB_”开头,且倒数第3个字符为 i的课程的详细情况。
SELECT * FROM Course WHERE Cname LIKE 'DB\_%i_ _' ESCAPE '\';
--like 匹配
--查询所有姓刘的
select sname,sno,sdept from Student where sname like '刘%'
-- 查询性欧阳的信息
select * from Student where sname like '欧阳%'
--‘欧阳____’对中文不太好用,下划线不准,但是英文很准
--like通配符的使用
select * from course where cname like 'sss\_sss' escape '\';
# 空值
使用谓词 IS NULL 或 IS NOT NULL
⬧ “IS NULL” 不能用 “= NULL” 代替
[例14] 某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。
查询缺少成绩的学生的学号和相应的课程号。
SELECT Sno,Cno FROM SC WHERE Grade IS NULL;
# 多重条件查询
❖用逻辑运算符AND和OR来联结多个查询条件
⬧ AND的优先级高于OR,但可以用括号改变优先级
⬧ 可用来实现多种其他谓词
➢[NOT] IN
➢[NOT] BETWEEN … AND …
[例15] 查询计算机系年龄在20岁以下的学生姓名。
SELECT Sname FROM Student WHERE Sdept= ‘CS’AND Sage<20;
# ⬧ order by子句
放在所有语句最后
❖使用ORDER BY子句
⬧ 可以按一个或多个属性列排序
⬧ 升序:ASC;降序:DESC;缺省值为升序
❖当排序列含空值时(SQL 默认空值未小,看系统)
⬧ ASC:排序列为空值的元组最后显示
⬧ DESC:排序列为空值的元组最先显示
❖当按多个属性排序时
⬧ 首先根据第一个属性排序,如果在该属性上有多个相同的值时,则按第二个属性排序,以此类推
例16] 查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
SELECT Sno,Grade
FROM SC
WHERE Cno = ' 3 '
ORDER BY Grade DESC;
[例17] 查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学
生按年龄降序排列。 SELECT *
FROM Student
ORDER BY Sdept,Sage DESC;
# ⬧ 聚集函数
[例18] 查询选修了课程的学生人数。
SELECT COUNT(DISTINCT Sno) FROM SC;
[例19] 计算1号课程的学生平均成绩。
SELECT AVG(Grade) FROM SC WHERE Cno= ' 1 '
--选修了2号课程学生的平均成绩
select avg(grade) from sc where cno='2'
--2号课程学生的总成绩
select sum(grade) from sc where cno='2'
--2号课程学生的总成绩 并展示时间
select sum(grade),getdate() from sc where cno='2'
-- -- where子句不允许出现具体函数
# ⬧ group by子句
❖使用GROUP BY子句分组
❖细化聚集函数的作用对象
⬧ 未对查询结果分组,聚集函数将作用于整个查询结果
⬧ 对查询结果分组后,聚集函数将分别作用于每个组
⬧ GROUP BY子句的作用对象是查询的中间结果表
⬧ 分组方法:按指定的一列或多列值分组,值相等的为一组
⬧ 使用GROUP BY子句后,SELECT子句的列名列表中只能出现分组属性和集 函数
⬧ 可以使用HAVING短语筛选最终输出结果
[例20] 求各个课程号及相应的选课人数。 (select后只允许分组属性与聚集属性)
SELECT Cno 课程号,COUNT(Sno) 人数
FROM SC
GROUP BY Cno; ( 分组属性)
[例21] 求各个课程号及相应的选课人数。
SELECT cno, count(sno)
FROM SC
GROUP BY cno
[例22] 查询选修了3门以上课程的学生学号。
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*) >3; (分组之后再筛选)
-- 查询各个课程号及其选课人数
select cno,count(sno) from sc group by cno
--每个系人数
select sdept,count(*) from Student group by sdept
SELECT sno
FROM SC
GROUP BY sno
HAVING count(*) >3;
# WHERE和HAVING子句区别
❖作用对象不同
⬧ WHERE子句作用于基表或视图,从中选择满足条件的元组。
⬧ HAVING短语作用于组,从中选择满足条件的组
3. ❖ 连接查询
# 连接查询基础知识
⬧ 同时涉及多个表的查询称为连接查询
⬧ 用来连接两个表的条件称为连接条件或连接谓词,其一般格式为:
⬧ 连接字段
➢连接谓词中的列名称为连接字段
➢连接条件中的各连接字段类型必须是可比的,但不必是相同的
# 连接操作执行过程
❖一种可能执行步骤
⬧ 首先在表1中找到第一个元组,然后从头开始扫描表2,逐一查找满足连接条件的元
组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组
⬧ 表2全部查找完后,再找表1中第二个元组,然后再从头开始扫描表2,逐一查找满
足连接条件的元组,找到后就将表1中的第二个元组与该元组拼接起来,形成结果
表中一个元组
⬧ 重复上述操作,直到表1中的全部元组都处理完毕
# 等值与非等值连接查询
❖若连接运算符为 = 时,称为等值连接
❖使用其他运算符时,称为非等值连接
❖在等值连接中,去掉目标列中的重复属性则为自然连接
等值与非等值连接查询
[例23] 查询每个学生及其选修课程的情况。
SELECT Student.* ,SC.*
FROM Student,SC
WHERE Student.Sno = SC.Sno;
--等值连接,不去掉重复行
select * from Student,sc where Student.sno=sc.sno;
select Student.*,sc.* from Student,sc where Student.sno=sc.sno;
[例24] 对[例33]用自然连接完成。
SELECT Student.Sno, Sname , Ssex , Sage , Sdept , Cno ,
Grade
FROM Student , SC
WHERE Student.Sno = SC.Sno;
# 自身连接
❖一个表与其自己进行连接,称为表的自身连接
⬧ 需要给表起别名以示区别
⬧ 由于所有属性名都是同名属性,因此必须使用别名前缀
自身连接
[例25] 查询每一门课的间接先修课(即先修课的先修课)。
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
# 外连接复合条件连接
外连接与普通连接的区别
未连接上的数组也保存
⬧ 普通连接操作只输出满足连接条件的元组
⬧ 外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输
出
外连接(Outer Join)
[例26] 查询每个学生及其选修课程的情况包括没有选修课程的学生----用外连接操作。
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUTER JOIN SC
ON Student.Sno = SC.Sno;
左外链接代表左面是主表,需要把主表没有选择的信息列出来
[例27] 用外连接、左连接、右连接完成。
外连接: SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST FULL OUTER JOIN Course SECOND
ON FIRST.Cpno = SECOND.Cno;
左连接: SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST LEFT OUTER JOIN Course SECOND
ON FIRST.Cpno = SECOND.Cno;
右连接: SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST RIGHT OUTER JOIN Course SECOND
ON FIRST.Cpno = SECOND.Cno;
外连接小结
❖左外连接
⬧ 左外连接符为left outer join
⬧ 列出左边关系中所有的元组
❖右外连接
⬧ 右外连接符为right outer join
⬧ 列出右边关系中所有的元组
❖外连接
⬧ 外连接符为full outer join
⬧ 列出左右两边关系中所有的元组
内连接(补充)
日常的查询都是内连接的
复合条件链接
WHERE子句中含多个连接条件时,称为复合条件连接
[例28] 查询选修2号课程且成绩在90分以上的所有学生的学号、姓名。
SELECT Student.Sno, student.Sname
FROM Student, SC
WHERE Student.Sno = SC.Sno /* 连接谓词*/
AND SC.Cno= ' 2 ' /* 其他限定条件 */
AND SC.Grade > 90; /* 其他限定条件 */
[例29] 查询每个学生的学号、姓名、选修的课程名及成绩。
SELECT Student.Sno,Sname,Cname,Grade
FROM Student,SC,Course /*多表连接*/
WHERE Student.Sno = SC.Sno
and SC.Cno = Course.Cno;
4. ❖ 嵌套查询
连接查询与嵌套查询可以等价
⬧ 嵌套查询概述
⬧ 一个SELECT-FROM-WHERE语句称为一个查询块
⬧ 将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询
子查询的限制 ➢不能使用ORDER BY子句(子查询分组无意义)
⬧ 层层嵌套方式反映了 SQL语言的结构化
⬧ 有些嵌套查询可以用连接运算替代
⬧ 嵌套查询分类
❖不相关子查询
子查询的查询条件不依赖于父查询,(子查询可以独立运行)
❖相关子查询
子查询的查询条件 依赖于父查询
⬧ 嵌套查询求解方法
❖不相关子查询
⬧ 是由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
❖相关子查询
⬧ 首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表;
⬧ 然后再取外层表的下一个元组;
⬧ 重复这一过程,直至外层表全部检查完为止。
⬧ 引出子查询的谓词
❖带有IN谓词的子查询
❖带有比较运算符的子查询
❖带有ANY或ALL谓词的子查询
❖带有EXISTS谓词的子查询 (重点的重点)
❖带有IN谓词的子查询
[例30] 查询与“刘晨”在同一个系学习的学生。
查询要求可以分步来完成
第一步: 确定“刘晨”所在系名
SELECT Sdept
FROM Student
WHERE Sname= ' 刘晨 ';
第二步:查找所有在CS系学习的学生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept= ' CS ';
❖构造嵌套查询
⬧ 将第一步查询嵌入到第二步查询的条件中
⬧ 此查询为不相关子查询。DBMS求解该查询时也是分步去做的。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname= ‘ 刘晨 ’);
------------------------------------------------------------
[例31] 查询选修了课程名为“信息系统”的学生学号和姓名。
SELECT Sno,Sname
FROM Student
WHERE Sno IN
(SELECT Sno
FROM SC
WHERE Cno IN
(SELECT Cno
FROM Course
WHERE Cname= ‘信息系统’));
❖带有比较运算符的子查询、
❖当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >)。
❖与ANY或ALL谓词配合使用带有比较运算符的子查询
重点:重点:重点:重点:重点:重点:重点:重点:重点:
[例32] 找出每个学生超过他选
修课程平均成绩的课程号。
SELECT Sno, Cno
FROM SC x
WHERE Grade >=
(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno = x.Sno);
❖可能的执行过程:
⬧ S1:从外层查询中取出SC的一个元组x,将元组x的Sno值(201215121)传送给内层查询。不确切时选择in
SELECT AVG(Grade)
FROM SC y
WHERE y.Sno='201215121';
S2:执行内层查询,得到值88(近似值),用该值代替内层查询,得到外层查询:
SELECT Sno, Cno
FROM SC x
WHERE Grade >=88;
⬧ S3:执行这个查询,得到
⬧ S4:外层查询取出下一个元组重复做上述1至3步骤,直到外层的SC元组全
部处理完毕。结果为:
(201215121,1)
(201215121,3)
(201215121,1)
(201215121,3)
(201215122,2)
❖带有ANY或ALL谓词的子查询
❖谓词语义
⬧ ANY:任意一个值
⬧ ALL:所有值
⬧ 需要配合使用的运算符
⬧ > ANY 大于子查询结果中的某个值
⬧ > ALL 大于子查询结果中的所有值
⬧ < ANY 小于子查询结果中的某个值
⬧ < ALL 小于子查询结果中的所有值
⬧ >= ANY 大于等于子查询结果中的某个值
⬧ >= ALL 大于等于子查询结果中的所有值
⬧ <= ANY 小于等于子查询结果中的某个值
⬧ <= ALL 小于等于子查询结果中的所有值
⬧ = ANY 等于子查询结果中的某个值
⬧ =ALL 等于子查询结果中的所有值(通常没有实际意义)
⬧ !=(或<>)ANY 不等于子查询结果中的某个值
⬧ !=(或<>)ALL 不等于子查询结果中的任何一个值
[例33] 查询其他系中比信息系任意一个(其中某一个)学生年龄小的学生姓名和年龄。
SELECT Sname,Sage
FROM Student
WHERE Sage < ANY
(SELECT Sage
FROM Student
WHERE Sdept= ' IS ')
AND Sdept <> ' IS ' ; /* 注意这是父查询块中的条件 */
[例34] 查询其他系中比计算机科学系所有学生年龄小的学生姓名和年龄。
SELECT Sname,Sage
FROM Student
WHERE Sage < ALL
(SELECT Sage
FROM Student
WHERE Sdept= ' CS ')
AND Sdept <> ' CS ' ;
❖带有EXISTS谓词的子查询
❖EXISTS谓词
❖NOT EXISTS谓词
❖不同形式的查询间的替换
❖相关子查询的效率
❖用EXISTS/NOT EXISTS实现全称量词
❖用EXISTS/NOT EXISTS实现逻辑蕴函
### EXISTS谓词
⬧ 存在量词
⬧ 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假 值“false”。
➢若内层查询结果非空,则外层的WHERE子句返回真值
➢若内层查询结果为空,则外层的WHERE子句返回假值
⬧ 由EXISTS引出的子查询,其目标列表达式通常都用* ,因为带EXISTS的子 查询只返回真值或假值,给出列名无实际意义
不关心查到了什么,只关心有没有
.
[例35] 查询所有选修了1号课程的学生姓名。
思路分析:
◼ 本查询涉及Student和SC关系。
◼ 在Student中依次取每个元组的Sno值,用此值去检查SC关系。
◼ 若SC中存在这样的元组,其Sno值等于
此Student.Sno值,并且其Cno= '1',则
取此Student.Sname送入结果关系。
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC /*相关子查询*/
WHERE Sno=Student.Sno AND Cno= '1');
### NOT EXISTS谓词
⬧ 若内层查询结果非空,则外层的WHERE子句返回假值
⬧ 若内层查询结果为空,则外层的WHERE子句返回真值
[例36] 查询没有选修了1号课程的学生姓名。
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT * (注意:*)
FROM SC
WHERE Sno = Student.Sno
AND Cno='1');
### 不同形式的查询间的替换
⬧ 一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替 换
⬧ 所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词 的子查询等价替换。
[例37] 查询与“刘晨”在同一个系学习的学生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname= ‘ 刘晨 ’);
SELECT Sno,Sname,Sdept
FROM Student S1
WHERE EXISTS
(SELECT *
FROM Student S2
WHERE S2.Sdept = S1.Sdept AND
S2.Sname = '刘晨 ';
### 用EXISTS/NOT EXISTS实现全称量词(难点)
⬧ SQL语言中没有全称量词 (For all)
⬧ 可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
否定之否定
[例38] 查询选修了全部课程的学生姓名。
不存在任何一门都没有选修的
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM Course
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno= Student.Sno AND
Cno= Course.Cno) );
.
⬧ SQL语言中没有蕴函
(Implication)逻辑运算
⬧ 可以利用谓词演算将逻辑蕴函
谓词等价转换为:
p → q ≡ p∨q
.
### 用EXISTS/NOT EXISTS实现逻辑蕴函(难点,重点)
[例39] 查询至少选修了学生201215122选修的全部课程的学生号码。
解题思路:
◼用逻辑蕴函表达:查询学号为x的学生,对所有的课程y,、
只要201215122学生选修了课程y,则x也选修了y。
◼形式化表示:
用P表示谓词 “学生201215122选修了课程y”
用q表示谓词 “学生x选修了课程y”
则上述查询为: (y) p → q
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS 学号
(SELECT *
FROM SC SCY
WHERE SCY.Sno = ' 201215122 ' AND
NOT EXISTS 课程号
(SELECT *
FROM SC SCZ
WHERE SCZ.Sno=SCX.Sno AND
SCZ.Cno=SCY.Cno)); 选择
5. ❖ 集合查询
并操作(UNION)
形式
<查询块>
UNION
<查询块>
⬧ 参加UNION操作的各结果表的列数必须相同;对应项的数据类型也必须相同
⬧ UNION:将多个查询结果合并起来时,系统自动去掉重复元组。
⬧ UNION ALL:将多个查询结果合并起来时,保留重复元组
.
[例40] 查询计算机科学系的学生及年龄不大于19岁的学生。
方法1:
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
方法2:
SELECT DISTINCT *
FROM Student
WHERE Sdept= 'CS' OR Sage<=19;
交操作(INTERSECT)
[例41] 查询计算机科学系的学生与年龄不大于19岁的学生的交集(INTERSECT)
SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19
AND代替了
请使用连接查询写出等价脚本
SELECT *
FROM Student
WHERE Sdept= 'CS' AND Sage<=19;
差操作(MINUS)
[例42] 查询计算机科学系的学生与年龄不大于19岁的学生的差集
SELECT *
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage <=19;
AND代替了
请使用连接查询写出等价脚本
SELECT *
FROM Student
WHERE Sdept= 'CS' AND
Sage>19
对集合操作结果的排序
❖ ORDER BY子句只能用于对最终查询结果排序,不能对中间结果排序
❖ 任何情况下,ORDER BY子句只能出现在最后,用在再查询最后,只有一次
❖ 对集合操作结果排序时,ORDER BY子句中用数字指定排序属性
SELECT小结
SELECT [ALL|DISTINCT]
<目标列表达式> [别名] [ ,<目标列表达式> [别名]] …
FROM <表名或视图名> [别名] [ ,<表名或视图名> [别名]] …
[WHERE <条件表达式>]
[GROUP BY <列名1>[,<列名1’>] ...
[HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC|DESC] [,<列名2’> [ASC|DESC] ] … ];
❖整条语句的含义:
⬧ 根据WHERE子句的条件表达式,从FROM子句指定的基本表或视图中找出
满足条件的元组,再按SELECT子句中的目标列表达式,选出元组中的属性
值形成结果表。
⬧ 如果有GROUP子句,则将结果按<列名1>的值进行分组,该属性列值相等
的元组为一个组,每个组产生结果表中的一条记录,通常会在每组中使用集
函数。如果GROUP子句带HAVING短语,则只有满足指定条件的组才输出。
如果有ORDER子句,则结果表还要按<列名2>的值的升序或降序排列。
Q & A
❖如何给列起别名,如何写计算列?
❖如何去掉重复行?
❖多个字段排序的顺序是怎样的?
❖Where和group by都是选择语句,他们的区别是什么?
❖ 使用SELECT语句:
⬧ 使用表别名和列别名;
⬧ 查询满足一定条件的元组;
⬧ 查询某些属性的值;
⬧ 通过在WHERE子句中放入连接条件,进行多表连接查询;
⬧ 利用DISTINCT去掉查询结果中的重复行;
⬧ 利用GROUP BY进行分组统计
⬧ 利用ORDER对查询结果按要求排序;
❖ 复杂查询
⬧ 嵌套查询
⬧ 集合查询
第五节 数据更新
❖数据的插入
⬧ 插入元组
语句格式
INSERT INTO <表名> [(<属性列1>[,<属性列2 >…)]
VALUES (<常量1> [,<常量2>] … )
不写属性列的话默认是所有的属性列
功能
⬧ 将新的元组插入到指定表
❖ INTO子句
⬧ 指定要插入数据的表名及属性列
⬧ 属性列的顺序可与表定义中的顺序不一致
⬧ 没有指定属性列:表示要插入的是一条完整的元组,且属性列属性与表定义中的顺序一致
⬧ 指定部分属性列:插入的元组在其余属性列上取空值
❖VALUES子句
⬧ 提供的值必须与INTO子句匹配
➢值的个数
➢值的类型
[例1] 将一个新学生记录(学号:201215128;姓名:陈冬;性别:男;
所在系:IS;年龄:18岁)插入到Student表中。
INSERT INTO Student (Sno, Sname, Ssex, Sdept, Sage)
VALUES ('201215128','陈冬' ,'男','IS',18);
注意是 values
[例2] 将学生张成民的信息插入到Student表中。
INSERT INTO Student
VALUES ('201215126', '张成民', '男', 18, 'CS');
前提是顺序是建表时的顺序
⬧ 插入子查询结果(重点)
❖语句格式
INSERT INTO <表名> [(<属性列1>[,<属性列2 >…)]子查询
❖功能
⬧ 将子查询结果插入指定表中
❖注意
⬧ 子查询的结果必须包含和insert的字段列表一样多的字段,并且数据类型兼容
[例3] 对每一个系,求学生的平均年龄,并把结果存入数据库。
第一步:建表
CREATE TABLE Deptage
(Sdept CHAR(15) , /* 系名*/
Avgage SMALLINT); /*学生平均年龄*/
第二步:插入数据
INSERT INTO Deptage(Sdept,Avgage) 插入
SELECT Sdept,AVG(Sage) /**子查询*/ 查询
FROM Student 来源
GROUP BY Sdept; 分组
❖数据的修改
❖语句格式(=是修改不是判等)
UPDATE <表名>
SET <列名>=<表达式>[,<列名>=<表达式>]…
[WHERE <条件>];
⬧ SET子句
➢指定修改方式、要修改的列、修改后取值
⬧ WHERE子句
➢指定要修改的元组,缺省表示要修改表中的所有元组
❖功能
⬧ 修改指定表中满足WHERE子句条件的元组
⬧ 修改某元组的值
[例4] 将学生201215121的年龄改为22岁。
UPDATE Student
SET Sage = 22
WHERE Sno=' 201215121 ';
⬧ 修改多个元组的值
例5] 将所有学生的年龄增加1岁。
UPDATE Student
SET Sage= Sage+1; (sage++是不对的)
所有学生成绩修改为0
update sc
set grade=0
where sno in(
select sno
form student
where sdept='cs'
)
所有计算机科学系学生成绩置空
update sc
set grade = null 判断空值不能用=。但是这里是赋值
where 'cs'=(
select sdept
from studdent
where student.sno=sc.sno
)
⬧ 带子查询的修改语句
[例6] 将计算机科学系全体学生的成绩置零。
UPDATE SC
SET Grade=0
WHERE 'CS'=
(SELETE Sdept
FROM Student
WHERE Student.Sno = SC.Sno);
.
❖DBMS在执行修改语句时会检查修改操作是否破坏表上已定义的完整性规则
⬧ 实体完整性
➢主码不允许修改
⬧ 用户定义的完整性
➢ NOT NULL约束
➢ UNIQUE约束
➢ 值域约束
❖数据的删除
❖定义
DELETE FROM <表名>
[WHERE <条件>];
⬧ WHERE子句
➢指定要删除的元组,缺省表示要删除表中的所有元组
❖功能
⬧ 删除指定表中满足WHERE子句条件的元组
⬧ 删除某一个元组的值
[例7] 删除学号为201215128的学生记录。
DELETE
FROM Student
WHERE Sno=' 201215128 ';
⬧ 删除多个元组的值
[例8] 删除所有学生的选课记录。
DELETE
FROM SC
⬧ 带子查询的删除语句
[例9] 删除计算机科学系所有学生的选课记录。
DELETE
FROM SC
WHERE 'CS' =
(SELECT Sdept
FROM student
WHERE student.Sno = SC.Sno)
方法2:
delete
form sc
where sno in
(
select sno
from student
where sdep[t='cs'
)
第六节 空值的处理
所谓空值就是“不知道”或“不存在”或无意义的值
❖空值的产生
❖空值的判断
❖空值的约束条件
❖空值的算术运算、比较运算和逻辑运算
第七节 视图 ( 只能看到部分数据 )
❖视图的特点
⬧ 虚表,是从一个或几个基本表(或视图)导出的表
⬧ 只存放视图的定义,不会出现数据冗余
⬧ 基表中的数据发生变化,从视图中查询出的数据也随之改变
❖基于视图的操作
⬧ 查询
⬧ 删除
⬧ 受限更新
⬧ 定义基于该视图的新视图
创建视图
create view is_student(sno,sname,sage)
as
select sno,sname,sage
from Student
where sdept='IS'
查询视图信息
select *
from is_student
通过视图插入信息
insert into is_student
values('123456789','杨康',19)
❖定义视图
❖语句格式
CREATE VIEW <视图名> [(<列名> [,<列名>]…)]
AS <子查询>
[WITH CHECK OPTION
⬧ 子查询不允许含有ORDER BY子句和DISTINCT短语
⬧ WITH CHECK OPTION
➢透过视图进行增删改操作时,不得破坏视图定义中的谓词条件(即子查询中的条件表达式)
[例10] 建立信息系学生的视图。 单表查询
CREATE VIEW IS_Student
AS
SELECT Sno, Sname, Sage
FROM student
WHERE Sdept= 'IS'
WITH CHECK OPTION 保证视图正确与否
从单个基本表导出,只是去掉了基本表的
某些行和某些列,保留了码————行列
子集视图
[例11] 建立信息系选修了1号课程的学生视图。 连接查询
CREATE VIEW IS_S1(Sno,Sname,Grade)
AS
SELECT Student.Sno,Sname,Grade
FROM Student,SC
WHERE Student.Sno=SC.Sno AND
Sdept= 'IS' AND
SC.Cno= '1';
[例12] 建立信息系选修了1号课程且成绩在90分以上的学生视图。
CREATE VIEW IS_S2
AS
SELECT Sno,Sname,Grade
FROM IS_S1 (在IS_S1基础上创建的)
WHERE Grade>=90;
[例13] 将学生的学号及他的平均成绩定义为一个视图。
CREATE VIEW S_G(Sno,Gavg)
AS 套结构
SELECT Sno,AVG(Grade) 子查询
FROM SC
GROUP BY Sno;
--建立所有女同学的所有属性视图
create view f_student(sno,sname,sex,age,dept)
as
select sno,sname,ssex,sage,sdept
from student
where ssex='女'
⬧ 删除视图
❖语句格式
DROP VIEW <视图名> [CASCADE];
⬧ 该语句从数据字典中删除指定的视图定义
⬧ 由该视图导出的其他视图定义仍在数据字典中,但已不能使用,必须显式删除
视图定义需要自己去删除
⬧ 删除基表时,由该基表导出的所有视图定义都必须显式删除
⬧ 如果CASCADE选项,则删除该视图时会把由它导出的视图一块删除
❖查询视图
早期方法,下面是新的方法
❖从用户角度:查询视图与查询基本表相同
❖DBMS实现视图查询的方法
⬧ 实体化视图(View Materialization)
➢有效性检查:检查所查询的视图是否存在
➢执行视图定义,将视图临时实体化,生成临时表
➢查询视图转换为查询临时表
➢查询完毕删除被实体化的视图(临时表)
视图消解法(View Resolution)
➢进行有效性检查,检查查询的表、视图等是否存在。如果存在,则从数据字典中取出视图的定义
➢把视图定义中的子查询与用户的查询结合起来,转换成等价的对基本表的查询
➢执行修正后的查询
[例14] 在信息系学生的视图中找出年龄小于20岁的学生。
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20;---不因该有,where不能聚集函数
◼ 视图消解法转换后的查询语句为:
SELECT Sno,Sage
FROM Student
WHERE Sdept= 'IS' AND Sage<20;
❖更新视图 (本质更新基本表)
❖用户角度:更新视图与更新基本表相同
❖DBMS实现视图更新的方法
⬧ 视图实体化法(View Materialization)
⬧ 视图消解法(View Resolution)
❖指定WITH CHECK OPTION子句后
DBMS在更新视图时会进行检查,
防止用户通过视图对不属于视图范围内的基本表数据进行更新
.
[例16] 将信息系学生视图IS_Student中学号201215122的学生姓名改为“刘辰” 。
UPDATE IS_Student
SET Sname= '刘辰'
WHERE Sno= ' 201215122 ';
转换后的语句:
UPDATE student
SET Sname= '刘辰'
WHERE Sno= ' 201215122 ' AND Sdept = ‘IS’;
❖一些视图是不可更新的,因为对这些视图的更新不能唯一地有意义 地转换成对相应基本表的更新(对两类方法均如此)
视图S_G为不可更新视图。
CREATE VIEW S_G (Sno,Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;
对于如下更新语句:
UPDATE S_G
SET Gavg=90
WHERE Sno= ‘201215121’;
无论实体化法还是消解法都无法将其转换成对基本表SC的更新
❖视图的作用
❖视图能够简化用户的操作
❖视图使用户能以多种角度看待同一数据
❖视图对重构数据库提供了一定程度的逻辑独立性
❖视图能够对机密数据提供安全保护
❖适当的利用视图可以更清晰的表达查询
总结
SQL是一个非过程化语言,使用者只需要说明“做什么”而不需要 说明“怎么做”
❖SQL是一个集定义、操作、查询和控制为一体的语言
❖如何使用Create Schema、Create Table语句和Create Index语句创 建模式、基本表和索引