关系数据库标准语言SQL
3.1 SQL概述
3.1.2 SQL的特点
-
高度非过程化
-
功能完并且一体化
-
统一的语法结构
-
语言简洁,易学易用
数据查询:
SELECT
数据定义:
CREATE
,DROP
数据操作:
INSERT
,UPDATE
,DELETE
数据控制:
GRANT
,REVOKE
3.2 SQL的定义功能
3.2.1基本表的定义
1.表结构的定义
CREATE TABLE<表名>
(<列名><数据类型>[列表完整性约束条件]
[,<列名><数据类型>[列表完整性约束条件]···]
[,<表级完整性约束条件>]
);
- 表名是所要定义的基本表的名字,表可以由一个或多个属性(列)组成
- 定义表的各个列时需要指明其数据类型及长度
类型 | 数据类型举例及缩写 | 说明 |
---|---|---|
Binary | BLOB | 以十六进制格式存储二进制字符串的值 |
BitString | BIT(n) BIT VARYING(n) |
这两种数据类型可以存储二进制和十六进制数据 |
Boolean | BOOLEAN | true、false或unknow |
Character | CHAR(n) VARCHAR(n) |
存储适宜的字符集中的任意字符组合 |
Numeric | INTEGER SMALLINT DECIMAL(i,j) FLOAT(p,s) REAL DOUBLE PERCISION |
这些数据类型存储数据的准确值(整数或小数)或近似值 |
Temporal | DATE TIME TIMESTAMP INTERVAL |
这些数据类型处理时间的值 |
- 完整性约束条件:
Primary Key
Foreign Key
【例3-1】
CREATE TABLE 学生
(学号 char(8) NOT NULL UNIQUE,
姓名 char(8),
性别 char(2),
出生年份 SMALLINT,
籍贯 char(8),
学院 char(15));
2.主关键词的定义
(1)在列出关系模型的属性时,在属性及其类型后加上保留字PRIMARY KEY
(2)在列出关系模型的所有属性后,再附加一个声明:
PRIMARY KEY(<属性1>[,<属性2>,···])
【例3-2】
- 方法一
CREATE TABLE 学生
(学号 char(8) PRIMARY KEY,
姓名 char(8),
性别 char(2),
出生年份 SMALLINT,
籍贯 char(8),
学院 char(15));
- 方法二
CREATE TABLE 学生
(学号 char(8),
姓名 char(8),
性别 char(2),
出生年份 SMALLINT,
籍贯 char(8),
学院 char(15)
PRIMARY KEY(学号));
【例3-3】
CREATE TABLE 课程
(课程号 SMALLINT NOT NULL UNIQUE,
课程名 char(15),
学时 SMALLINT,
开课学期 char(4),
课程性质 char(15),
primary key(课程号));
【例3-4】
CREATE TABLE 学习
(学号 char(8),
课程号 char(8),
成绩 smallint,
primary key(学习,课程号));
3. 外部关键字的定义
(1)如果外部关键词只有一个属性,可以在它的属性名和类型后面直接用REFERENCES
说明它参照了某个表的某些属性(必须是PRIMARY KEY
)
REFERENCES <表名> (<属性>)
(2) 在属性列后面添加
FOREIGN KEY(<属性 1>REFERENCES<表名>(<属性2>))
【例3-5】
CREATE TABLE 学习
(学号 char(8),
课程号 char(8),
成绩 smallint,
primary key(学习,课程号)
FOREIGN KEY(学号 references 学生(学号))
FOREIGN KEY(课程号 references 课程(课程号));
4.默认值的定义
性别 char(2) default '男';
年龄 smallint default 19;
3.2.2 基本表的修改和删除
ALTER TABLE 学生 ADD COLUMN 年龄 SMALLINT;
ALTER TABLE 课程 ALTER COLUMN 课程名 CHAR(20);
ALTER TABLE 学生 DROP COLUMN 年龄;
DROP TABLE <表名>
3.2.3 索引的建立和删除
3.3 数据查询
SELECT [ALL|DISTINCT]<属性列表>
FROM <表名或视图名>[,[表名或视图名]]···
[WHERE <条件表达式>]
[GROUP BY <列名>]
[HAVING <条件表达式>]
[ORDER by<列名>[]];
3.3.1 单表查询
- 选择表中的若干列(投影)
- 选择表中的若干元组(选择)
- 对查询进行分组
- 使用集函数
- 对查询结果排序
1.SQL中的投影
【例3-12】
SELECT 姓名,籍贯
FROM 学生;
【例3-13】
SELECT DISTINCT 籍贯
FROM 学生;
【例3-14】
SELECT *
FROM 学生;
【例3-15】
查询学生学号和年龄
select 学号,year(now())-出生年份
from 学生;
【例3-16】
给列表别名
select 学号,year(now())-出生年份 as 年龄
from 学生;
2. SQL中的选择运算
查 询 条 件 | 谓 词 |
---|---|
比较 | =, <>, >, <, >=, <= |
算数运算 | +,-,*,/ |
确定范围 | BETWEEN AND, NOT BETWEEN AND |
确定集合 | IN, NOT IN |
字符匹配 | LIKE, NOT LIKE |
空值 | IS NULL, IS NOT NULL |
多重条件 | AND,OR |
1)比较运算
【例3-17】
查询所有不及格课程的学生的学号,课程号及成绩
select 学号,课程号,成绩
from 学习
where 成绩<60;
【例3-18】
查询有不及格课程的学生的学号
select distinct 学号
from 学习
where 成绩<60;
2)多重运算和算术运算
【例3-19】
在学生表中找出信电学院2000年后出生的学生的记录
select *
from 学生
where 学院='信电' and 出生年份>2000;
3)确定范围
【例3-20】
select 姓名,性别,学院,出生年份
from 学生
where 出生年份 between 1996 and 1998;
4)确定集合
【例3-21】
select 学号,姓名,出生年份
from 学生
where 学院 in ('信电','理学院','计算机');
5)字符匹配
[not] like '<匹配串>' [ESCAPE'<转码字符>']
6)空值
3.对查询结果进行分组
select 课程号,count(学号) as 选课人数
from 学习
group by 课程号;
【例3-27】
select 学号,count(课程号) as 选修课程数
from 学习
where 学号 between '091501' and '091506'
group by 学号
having 选修课程数>3;
4.使用集函数
COUNT([DISTINCT|ALL]*) #统计原则个数
COUNT([DISTINCT|ALL]<列名>)#统计一列中值的个数
SUM([DISTINCT|ALL]<列名>)#计算一列值的总和
AVG([DISTINCT|ALL]<列名>)#平均值
MAX([DISTINCT|ALL]<列名>)#最大值
MIN([DISTINCT|ALL]<列名>)#最小值
#查询学生总人数
select count(*)
from 学生;
#查询计算机学院学生的平均年龄
select avg(year(now())-出生年份) as 平均年龄 #别忘了别名
from 学生
where 学院='计算机';
#查询学习180101号课程的学生最高分数
select max(成绩) as 最高分
from 学习
where 课程号='180101'
5.对查询结果排序
select 学号,成绩
from 学习
where 课程='180102'
order by 成绩 desc;
查询全体学生情况,查询结果按所在学院的名称升序排列,对同一学院中给的学生按年龄降序排列
select *
from 学生
order by 学院 asc, year(now())-出生年份 desc;
3.3.2 连接查询
- 等值连接和非等值连接
- 自身连接查询
- 外连接查询
- 复合条件连接查询
- 集合运算查询
(1)ANSI 方式
【例3-33】
#查询每个学生及其选修课程的情况
select 学生.*,学习.*
from 学生 INNER JOIN 学生.学号=学习.学号;
(2) theta方式
select 学生.*,学习.*
from 学生,学习
where 学生.学号=学习.学号;
1.等值与非等值连接查询
[<表名1>.]<列名1><比较运算符>[<表名2>.]<列名> #比较运算符为=时为等值连接
#自然连接“学生表”和“学习表”
select 学生.学号,姓名,性别,出生年份,学院,课程号,成绩
from 学生,学习
where 学生.学号=学习.学号
2.自身连接查询
#求一门课程的间接先修课
select first.课程号 as 课程号,first.课程名 as 课程名,second.课程名 as 间接选修课
from 课程 as first,课程 as second
where first.先修课课程号=second.课程号;
3. 外连接查询
1)左外连接
规定所有记录都应该从连接语句左侧的表中返回。当右侧表中没有匹配的记录时,左表中该记录依然会返回,而右侧表中的列值将自动填充NULL 值
#查询所有学生的姓名以及他们选修课程的课程号和成绩
select 姓名,课程号,成绩
from 学生,学习
where 学生.学号(+)=学习.学号;
2) 右外连接
规定所有记录都应该从连接语句右侧的表中返回。当右侧表中没有匹配的记录时,左表中该记录依然会返回,而右侧表中的列值将自动填充NULL 值
4.复合条件连接查询
#查询选修180101号课程且成绩在90分以上的学生学号,姓名以及成绩
select 学生.学号,姓名,成绩
from 学生,学习
where 学生.学号=学习.学号
and 课程号='180101'
and 成绩>90;
#ANSI
select 学生.学号,姓名,成绩
from 学生 JOIN on 学生.学号=学习.学号
and 课程号='180101'
and 成绩>90;
#查询每个学生及其选修的课程名及其成绩
select 学生.学号,姓名,课程名,成绩
from 学生,课程,学习
where 学生.学号=学习.学号
and 学习.课程号=课程.课程号;
#ANSI
select 学生.学号,姓名,课程名,成绩
from 学生
JOIN 学习 on 学生.学号=学习.学号
JOIN 课程 on 学习.课程号=课程.课程号;
5.集合运算连接查询
- 并:
UNION
- 交:
INTERSECT
- 差:
EXCEPT
#查询选修了180101号或180102号课程或二者都选修了的学生学号、课程号和成绩
(select 学生.学号,课程号,成绩
from 学生,学习
where 学生.学号=学习.学号 and 课程号='180101')
union
(select 学生.学号,课程号,成绩
from 学生,学习
where 学生.学号=学习.学号 and 课程号='180102')
3.3.3 嵌套查询
- 相关子查询
- 不相关子查询
1. 带有IN谓词的子查询
#查询选修了“数据库原理”课程的学生学号和姓名
select 学号,姓名
from 学生
where 学号 in
(select 学号
from 学习
where 课程号 in
(select 课程号
from 课程
where 课程名='数据库原理'));
#用IN来实现交运算,大部分DBMS不支持INTERSECT
SELECT 学号,课程号,成绩
from 学习
where 课程号='180101' and 学号 in
(select 学号
from 学习
where 课程号='180102' )
#NOT IN 差运算
SELECT 学号,课程号,成绩
from 学习
where 课程号='180101' and 学号 not in
(select 学号
from 学习
where 课程号='180102' )
2.带有比较运算符的查询
3.带有ANY或ALL谓词的子查询
#查询其他学院比计算机学院某个学生年龄小的学生名单
select 姓名
from 学生
where year(now())-出生年份 < ANY
(select year(now())-出生年份
from 学生
where 学院='计算机')
and 学院!='计算机'
order by year(now())-出生年份 desc;
4.带有EXISTS谓词的子查询
#EXISTS实现交运算
SELECT s1.学号,s1.课程号,s1.成绩
from 学习 as s1
where s1.课程号='180101' and exists
(select *
from 学习 as s2
where s2.课程号='180102' and s1.学号=s1.学号);
#EXISTS实现差运算
SELECT s1.学号,s1.课程号,s1.成绩
from 学习 as s1
where s1.课程号='180101' and not exists
(select *
from 学习 as s2
where s2.课程号='180102' and s1.学号=s1.学号);
#选修过全部课程的学生的学号和姓名
select 学号,姓名
from 学生
where not exists
(select *
from 课程
where not exists
(select *
from 学习
where 学习.学号=学生.学号 and 学习.课程号=课程.课程号 )
)
#查询至少选修了091501号学生选修的全部课程的学生学号
select 学号
from 学生
where not exists
(select *
from 学习 as First
where First.学号='091501' and not exists
(select *
from 学习 as Second
where Second.学号=学生.学号 and Second.课程号=First.课程号))
3.4 数据更新
- 插入
- 删除
- 修改
3.4.1 插入数据
1.插入单个元组
INSERT
INTO <表名> [<属性列>]
Values (<常量1>[,<常量2>···])
INSERT INTO 学习(学号,课程号)
VALUES('091530','080102')
2.插入子查询结果
INSERT
INTO <表名> [<属性列>]
子查询;
#统计每门课的平均分
CREATE TABLE 课程平均分
(课程号 CHAR(8)
课程名 CHAR(15)
平均分 DOUBLE);
INSERT
INTO 课程平均分(课程号,课程名,平均分)
SELECT 课程号,课程名,AVG(成绩)
FROM 课程,学习
WHERE 课程.课程号=学习.课程号
GROUP BY 课程号,课程名;
3.4.3修改数据
UPDATE <表名>
SET <列名>=<表达式>
[WHERE <条件>];
1.更改表中一个元组
UPDATE 学生
SET 籍贯='江苏'
WHERE 学号='091611';
2.更新表中多个元组的数据
#将180101号课程的成绩增加一分
UPDATE 学习
SET 成绩=成绩+1
WHERE 课程号='180101';
3.带子查询的修改
UPDATE 学习
SET 成绩=0
WHERE 学号 IN
(SELECT 学号
FROM 学生
WHERE 学院='计算机');
3.5 视图
3.5.1 建立视图
create view <视图名>[(<列名>)]
as <子查询>
[WITH CHECK OPTION];
WITH CHECK OPTION
表示对视图进行插入、删除和更新操作时要保证发生变动的行慢则视图定义中的谓词条件(即子查询中的条件)
#建立计算机学院选修了“数据库原理”这门课的学生的视图
CREATE VIEW DB_S1
AS
SELECT 学生,学号,姓名,籍贯,学院,成绩
FROM 学习,学生,课程
WHERE 学院='计算机'AND学生.学号=学习.学号 AND 学习.课程号=课程.课程号 and 课程名='数据库原理'
#定义一个反映学生年龄的视图
CREATE VIEW BT_S(学号,姓名,年龄)
as
SELECT 学号,姓名,year(now())-出生年份 AS 年龄
FROM 学生