Transcript 数据库原理及应用
第5章 关系数据库的结构化查询语言SQL
本章主要内容
本章介绍关系数据库标准语言SQL。主要内容包括:
数据定义、数据操纵、数据控制和数据约束等。
(1)SQL数据库的体系结构,SQL的组成。
(2)SQL的数据定义:SQL模式、基本表和索引的创建和撤销。
(3)SQL的数据查询:
SELECT语句的句法,SELECT语句的几种形式及各种限定,
基本表的联接操作。
(4)SQL的数据更新:插入、删除和修改语句。
(5)视图的创建和撤消,对视图更新操作的限制。
(6)嵌入式SQL:
预处理方式,使用规定,使用技术,卷游标,动态SQL语句。
关系数据库的结构化查询语言SQL
5.1 SQL概述
5.2 SQL的数据定义语言
5.3 SQL数据查询
5.4 SQL聚集函数(Aggregation)
5.5 SQL数据更新
5.6 SQL中的视图
5.7 嵌入式SQL
本章小结
5.1 SQL概述
1)SQL的发展历程
SQL语言1974年由Boyce和Chamberlin提出,并首先
在IBM公司研制的关系数据库系统System R上实现。
1986年10月,经美国国家标准局(ANSI)的数据库委
员会批准了SQL作为关系数据库语言的美国标准,并
公布了标准SQL文本。
1987年6月国际标准化组织(ISO)将其采纳为国际标准,
称为“SQL86”。
相继出现了“SQL89”、“SQL2(SQL92)”、“SQL3”。
SQL已成为关系数据库领域中的一个主流语言:
首先,各个数据库产品厂家纷纷推出了自己的支持
SQL的软件或与SQL接口的软件。
其次,SQL在数据库以外的其他领域也受到了重视。
不少软件产品将SQL的数据检索功能与面向对象技术、
图形技术、软件工程工具、软件开发工具、人工智
能语言等相结合,开发出功能更强的软件产品。
2)SQL数据库的体系结构
SQL用户
用户1
用户2
外模式
用户3
用户4
视图V2
视图V1
模式
基本表B1
基本表B2
基本表B3
基本表B4
内模式
存储文件S1
存储文件S2
存储文件S3
存储文件S4
SQL数据库的体系结构的特征:
一个SQL模式是表和约束的集合。
一个表(TABLE)是行的集合。每行是列的序列,
每列对应一个数据项。
一个表可以是一个基本表,也可以是一个视图。
一个基本表可以跨一个或多个存储文件,一个存储
文件也可存储一个或多个基本表。
用户可以用SQL语句对视图和基本表进行查询等操
作。
SQL用户可以是应用程序,也可以是终端用户。
3)SQL的组成
(1)数据定义语言(Data Definition Language,简称DDL)
用于定义SQL模式、基本表、视图和索引。
(2)查询语言(Query Language,简称QL)
用于数据查询。
(3)数据操纵语言(Data Manipulation Language,简称DML)
用于数据的增、删、修改。
(4)数据控制语言(Data Control Language,简称DCL)
用于数据访问权限的控制。
5.2
SQL的数据定义语言
5.2.1 数据类型
5.2.2 基本表模式的定义
5.2.3 基本表的修改和删除
5.2.4 域
5.2.5 索引的建立和删除
5.2.1 数据类型
数据类型
说明符
备注
定长字符串
CHAR(n)
按固定长度n存储字符串,如果实际字符串长度长小于n,后
面填空格符;如果实际字符串长大于n,则报错。
变长字符串
整数
VARCHAR(n)
INT
按实际字符串长度存储,但字符长度不得超过n,则报错。
常见的长整数,字长32位
短整数
SMALLINT
字长16位
十进制数
DECIMAL(n,d)
n为十进制数总位数(不包括小数点),d为小数据点后的十进
制位数
浮点数
FLOAT
一般指双精度浮点数,即字长64位
定长位串
BIT(n)
二进制位串,长度为n,n的缺省值为1
变长位串
BITVARING(n)
按实际二进制位串存储,但最长不得超过n位,否则报错
日期
DATE
时间
TIME
时标
TIMESTAMP
格式为“yyyymmdd”, yyyy表示年份,范围为0001~9999;mm
表示月份,范围为1~12;dd表示日,范围为1~31。
格式为“hhmmss”,hh表示小时,范围为0~24;mm为分钟,
ss表示秒,范围都是0~59。
格式为“yyyymmddhhmmssnnnnnn”,其中“nnnnnn”表示
微秒,范围为0~99999,其他符号的意义同上。
5.2.2 数据表模式的定义
1)定义数据库的语句格式为 :
CREATE DATABASE database_name
[ ON
( NAME = file_name ,
FILENAME = 'os_file_name '
[ , SIZE = size ]
[ , MAXSIZE = { max_size | UNLIMITED } ]
[ , FILEGROWTH = growth_increment ] )]
[LOG ON
( NAME = logical_ file_name ,
FILENAME = 'os_file_name '
[ , SIZE = size ]
[ , MAXSIZE = { max_size | UNLIMITED } ]
[ , FILEGROWTH = growth_increment ] )]
事例
CREATE DATABASE studb
ON
( NAME = 'studb_dat',
FILENAME = 'd:\studb.mdf' ,
SIZE = 4,
MAXSIZE = 10,
FILEGROWTH = 1)
LOG ON
( NAME = 'studb_log',
FILENAME = 'd:\studb_log.LDF' ,
SIZE = 1,
FILEGROWTH = 10%);
2)基本表SQL定义语句格式
定义基本表的语句格式为 :
CREATE TABLE<表名>(
<属性名1 > <类型1>[NOT NULL] [UNIQUE]
[,<属性名2><类型2] [NOT NULL] [UNIQUE] ]…)
[其他参数];
例5-1:学生成绩数据库含有三张表:
学生关系:S(SNO,SNAME,SEX, AGE, DNAME)
课程关系:C(CNO, CNAME, CREDIT, PRE_CNO)
选课关系:SC(SNO, CNO, SCORE)
可用下列SQL语句来实现:
SQL事例
CREATE TABLE S
( SNO CHAR(6) PRIMARY KEY,
SNAME CHAR(8) NOT NULL,
AGE SMALLINT,
SEX CHAR(1),
DNAME VARCHAR(12));
CREATE TABLE C
( CNO CHAR(2) NOT NULL,
CNAME VARCHAR(24) NOT NULL,
CREDIT SMALLINT,
PRE_CNO CHAR(2),
PRIMARY KEY(CNO));
CREATE TABLE SC
( SNO CHAR(6) NOT NULL,
CNO CHAR(2) NOT NULL,
SCORE SMALLINT,
PRIMARY KEY(SNO,CNO),
FOREIGN KEY(SNO)
REFERENCES S ON DELETE CASCADE,
FOREIGN KEY(CNO)
REFERENCES C ON DELETE NO ACTION);
3)主关键字定义
方法1:一个关系的主关键字由一个或几个属性构成,在
CREATE TABLE中使用保留字PRIMARY KEY声明主关
键字:
(1)在列出关系模式的属性时,在属性及其类型后加上保留
字PRIMARY KEY,表示该属性是主关键字;
(2)在列出关系模式的所有属性后,再附加一个声明:
PRIMARY KEY(<属性1>[,<属性2>…])
如果关键字由多个属性构成,则必须使用方法(2)。
SQL事例
CREATE TABLE S
( SNO CHAR(6) PRIMARY KEY, /*第一种方式*/
SNAME CHAR(8) NOT NULL,
AGE SMALLINT,
SEX CHAR(1),
DNAME VARCHAR(12));
CREATE TABLE C
( CNO CHAR(2) NOT NULL,
CNAME VARCHAR(24) NOT NULL,
CREDIT SMALLINT,
PRE_CNO CHAR(2),
PRIMARY KEY(CNO));
/*第二种方式*/
CREATE TABLE SC
( SNO CHAR(6) NOT NULL,
CNO CHAR(2) NOT NULL,
SCORE SMALLINT,
PRIMARY KEY(SNO,CNO),
/*第二种方式*/
FOREIGN KEY(SNO)
REFERENCES S ON DELETE CASCADE,
FOREIGN KEY(CNO)
REFERENCES C ON DELETE RESTRICT);
主关键字定义
方法2:使用保留字UNIQUE来说明关键字。
它可以出现在PRIMARY KEY出现的任何地方,可以在同一个关
系模式中出现多次。
例如,在不出现同名同姓的情况下也可以将上面的定义改写为:
CREATE TABLE S
( SNO CHAR(6) UNIQUE,
SNAME CHAR(8) UNIQUE,
SEX CHAR(1),
AGE SMALLINT,
DNAME VARCHAR(12));
4)外部关键字的定义
在SQL中,有两种方法用于说明一个外部关键字:
方法1:在表的属性名和类型后面直接用"REFERENCES"说明它参
照了某个表的某些属性(必须是主关键字),其格式为:
REFERENCES <表名>(<属性>)
这种方法主要在外部关键字只有一个属性时可以使用。
方法2:在CREATE TABLE语句的属性列表后面增加一个或几个
外部关键字说明,其格式为:
FOREIGN KEY <属性> REFERENCES <表名>(<属性>)
其中,第一个“属性”是外部关键字,第二个“属性”是被参照的
CREATE TABLE SC
属性。
( SNO CHAR(6) NOT NULL,
CNO CHAR(2) NOT NULL,
SCORE SMALLINT,
PRIMARY KEY(SNO,CNO),
FOREIGN KEY(SNO)
REFERENCES S ON DELETE CASCADE,
FOREIGN KEY(CNO)
REFERENCES C ON DELETE RESTRICT);
表名- 1
CREATE TABLE
(
字值
列名- 1
类型- 1
DEFAULT
NOT NULL
基
本
表
定
义
格
式
图
示
NULL
UNIQUE
,
,
PRIMARY KEY
,
FOREIGN KEY
(
列表名- 1
(
外键名
表名- 2
REFERENCES
RESTRICT
ON DELETE
CASCADE
SET NULL
,
CHECK
(
USER
条件
)
;
(
)
列表名- 2
)
5.2.3 基本表的修改和删除
1)增加新的属性
ALTER TABLE [<表的创建者名.>] <表名>
ADD<属性名><类型>;
例 如 : 在 表 S 中 增 加 属 性 “ BIRTHDATE”, “HOSTADDR” 和
“COMMADDR”:
ALTER TABLE S ADD BIRTFIDATE DATETIME;
ALTER TABLE S ADD HOSTADDR VARCHAR(32);
ALTER TABLE S ADD COMMADDR VARCHAR(32);
2)删除原有属性的语句为
ALTER TABLE <表名>
DROP
<属性名> [CASCADE| RESTRICT];
例如:在表S中删除“AGE”:
ALTER TABLE S DROP AGE;
SQL SERVER 2000:
ALTER TABLE S DROP column AGE;
3)基本表的删除
在SQL中删除一个无用表的操作是非常简单的,其语句格式为:
DROP TABLE <表名>;
主键修改
4)补充定义主键
由于SQL并不要求每个表都定义主键,在需要时可以通过补充
定义主键命令来定义主键。
ALTER TABLE <表名> ADD PRIMARY KEY(<属性名表>);
SQL SERVER 2000:
ALTER TABLE <表名> ADD CONSTRAINT constraint_name
PRIMARY KEY(<属性名表>);
5)撤销主键定义
利用下列的主键撤销命令可以暂时撤销主键定义:
ALTER TABLE <表名> DROP PRIMARY KEY;
SQL SERVER 2000:
ALTER TABLE <表名> DROP CONSTRAINT constraint_name
外键修改
6)补充定义外键
ALTER TABLE <表名>
ADD FOREIGN KEY <属性> REFERENCES <表名>(<属性>)
[ON DELETE { RESTRICT | CASCADE | SET NULL}];
7)撤消外键定义
ALTER TABLE <表名> DROP FOREIGN KEY <外键名>
5.2.4 域
定义一个域的方法是:
CREATE DOMAIN <域名> AS <数据类型> ;
通过已定义域名来说明一个属性类型,其格式是:
<属性名1>[,<属性名2>,…]<域名>;
例 如 : 为 表 S 的 HOSTADDR 和 COMMADDR 定 义 一 个 域
ADDRDOMAIN:
CREATE DOMAIN ADDRDOMAIN AS VARCHAR(36)
DEFAULT 'unknow';
用 域 “ ADDRDOMAIN” 来 说 明 属 性 “ HOSTADDR” 和
“COMMADDR”的类型。
HOSTADDR,COMMADDR ADDRDOMAIN;
删除一个域定义的语句是:
DROP DOMAIN <域名>;
5.2.5 索引的建立和删除
建立索引的语句格式为:
CREATE [UNIQUE] INDEX <索引名>
ON 基本表名(<属性名1>[ASC|DESC]
[,<属性名2>[ ASC|DESC]…]);
例如,对表S建立以下索引
CREATE UNIQUE INDEX SNO_INDEX ON S (SNO);
CREATE UNIQUE INDEX SNAME_ADDR_INDEX
ON S (SNAME ASC,HOSTADDR DESC);
删除索引的语句格式:
DROP INDEX <索引名>;
5.3 SQL数据查询
5.3.1 ALPHA关系演算语言
5.3.2 SQL查询语句格式
5.3.3 简单查询
5.3.4 复杂查询
5.3.1 ALPHA关系演算语言
语名的基本格式是:
操作语句 工作空间名(表达式):操作条件
(1)简单检索
例
查询所有被选修课程的课程号。
GET W(SC.SNO)
例 查询所有学生的数据。
GET W(STUDENT)
(2)限定的检索
例
查询计算机系中年龄小于20岁的学生的学号和年龄。
GET W(STUDENT.SNO,STUDENT.AGE):
STUDENT.DNAME='计算机' ∧ STUDENT.AGE<20
ALPHA关系演算语言
(3)带排序的检索
例 查询计算机系学生的学号、年龄,并按降序排序。
GET W(STUDENT.SNO,STUDENT.AGE):
STUDENT.DNAME='计算机' DOWN STUDENT.AGE
(4)带定额的检索
例 取出一个计算机系学生的学号。
GET W(1)(STUDENT.SNO):STUDENT.DNAME='计算机'
所谓带定额的检索是指检索出指定个数的元组,方法是在W后括号
中加上定额数量。
排序和定额可以一起使用。
例 查询计算机系年龄最大的3个学生的学号及年龄。
GET W(3)(STUDENT.SNO,STUDENT.AGE):
STUDENT.DNAME='计算机' DOWN STUDENT.AGE
ALPHA关系演算语言
(5)用元组变量的检索
因为元组变量是在某一关系范围内变化的,所以元组变量又称
为范围变量。
元组变量主要有两个方面的用途:
① 简化关系名。
②操作条件中使用量词时必须用元组变量。
例 查询计算机系学生的姓名。
RANGE Student X
GET W(X.SNAME):X.DNAME='计算机'
这里元组变量X的作用是简化关系名Student。
(6)用存在量词的检索
例
查询选修C2课程的学生姓名。
RANGE SC X
GET W(STUDENT.SNAME):
存在X(X.SNO=Student.SNO ∧X.CNO='C2')
例 查询选修了其直接先行课程为C2课程的学生学号。
RANGE Course CX
GET W(SC.SNO):
存在CX(CX.SNO=SC.SNO ∧CX.PRE_CNO='C2')
例 查询至少选修一门其先行课程为C1课程的学生姓名。
RANGE
Course CX
SC SCX
GET W(Student.SNAME):存在SCX(SCX.SNO=Student.SNO∧
存在CX(CX.CNO=SC.CNO∧CX.PRE_CNO='C1'))
本例中的元组关系演算公式可以变换为前束范式的形式:
GET W(Student.SNAME):存在SCX存在CX(SCX.SNO=Student.SNO∧
CX.CNO=SC.CNO∧CX.PRE_CNO='C1')
(7)带有多个关系的表达式的检索
上面所举的各个例子中,虽然查询时可能会涉及多个关系,即公式中
可以涉及多个关系,但查询都只在一个关系中,即表达式中只有一个
关系。表达式中可以有多个关系的。
例 查询成绩为90分以上的学生姓名和课程名。
本查询所要求的结果学生姓名和课程名分别在Student和Course两个
关系中。
RANGE SC SCX
GET W(Student.SNAME,Course.CNAME):
存在SCX(SCX.SCORE≥90∧
SCX.SNO= Student.SNO∧Course.CNO= SCX.CNO)
(8)用全称量词的检索
例 查询没有选修C1课程的学生姓名。
本查询所要求的结果学生姓名和课程名分别在Student和Course两个关
系中。
RANGE Course CX
GET W(Student.SNAME):
任意SCX(SCX.SNO≠Student.SNO∨SCX.CNO≠'C1')
本例实际上可以用存在量词来表示:
GET W(Student.SNAME):
→存在SCX(SCX.SNO=Student.SNO∧SCX.CNO='C1')
(9)用两种量词的检索
例 查询了选修全部课程的学生姓名。
RANGE Course CX
SC SCX
GET W(Student.SNAME):任意 CX 存在 SCX(
SCX.SNO=Student.SNO∧SCX.CNO=CX.CNO)
(10)用蕴函的检索
例 查询至少选修了学生S1所选课程的学生的学号。
RANGE Course CX
SC SCX
SC SCY
GET W(Student.SNO):
任意 CX(存在 SCX(SCX.SNO='S1'∧SCX.CNO=CX.CNO)
=>存在 SCY(SCY.SNO=Student.SNO∧SCY.CNO=CX.CNO))
(11)集函数
提供了COUNT、TOTAL、MAX、MIN、AVG等集函数。
例
查询学生所在系的数目
GET W(COUNT(Student.DNAME))
例
查询计算机系学生的平均年龄
GET W(AVG(Student.AGE):Student.DNAME='计算机')
5.3.2 SQL查询语句格式
查询语句的基本部分:
SELECT <属性列表>
FROM <基本表>(或视图)
[WHERE <条件表达式>];
关系代数
A ,,A
1
n
( F ( R 1 R m ))
其SQL语句为:
SELECT A1,…,An
FROM R1,…,Rm
WHERE F
条件表达式F
条件表达式F中可使用下列运算符:
算术比较运算符:<、<=、>、>=、=、<>或!=。
逻辑运算符:AND、OR、NOT。
集合运算符:IN、NOT IN。
谓词:EXISTS(存在量词)、ALL、SOME、UNIQUE。
聚合函数:AVG、MIN、MAX、SUM、COUNT。
F中运算对象还可以是另一个SELECT语句,即SELECT语句
可以嵌套。
5.3.3简单查询
最简单的SQL查询只涉及到一个关系,类似于关系代数
中的选择运算。
例如:关系代数中的选择运算σDNAME=‘计算机’ (S)的SQL查询语
句如下例5.5。
例5.5:在表S中找出计算机系学生的学号、姓名等信息。
SELECT SNO,SNAME, AGE, SEX,DNAME
FROM S
WHERE DNAME='计算机';
例5.5 查询结果
(a)学生关系表
(b)例5-5查询结果
SNO
SNAME
AGE
SEX
DNAME
S1
程宏
19
M
计算机
SNO
SNAME
AGE
SEX
DNAME
S3
刘莎莎
18
F
电子
S1
程宏
19
M
计算机
S4
李刚
20
M
自动化
S9
王敏
20
F
计算机
S6
蒋天峰
19
M
电气
S9
王敏
20
F
计算机
用通配符“*”简化表示所有属性名 :
例5.6:求计算机系学生的详细信息。
SELECT *
FROM S
WHERE DNAME='计算机';
1)SQL中的投影
利用SELECT子句指定属性的功能完成关系代数中的投影运算。
例5.7:在表S中找出计算机系学生的学号和姓名。
SELECT SNO,SNAME
FROM S
WHERE DNAME=‘计算机’;
在SELECT子句中增加保留字“AS”和相应的别名,使结果表中的
某些属性名不同于基本表中的属性名,如:
例5.8:将例5-7结果表中的SNO换名为学号,将SNAME改为姓名:
SELECT SNO AS 学号,SNAME AS 姓名
FROM S
WHERE DNAME='计算机';
SELECT子句中可以出现计算表达式,从而可以查询经过计算
的值。
例5.9:求学生的学号和出生年份。
SELECT SNO,2009-AGE
FROM S;
SELECT后面可以是属性名,也可以是属性名与常数组成的算
术表达式,还可以是字符串。
例5.10:将例5.9改为:
SELECT SNO, 'BIRTH_ YEAR:',2009-AGE
FROM S;
2) SQL中的选择运算
通过在WHERE子句中指定相应的条件表达式,完成关
系代数中的选择运算。
例5.11:列出表S中计算机系年龄小于20岁的学生的情况。
SELECT *
FROM S
WHERE DNAME='计算机' AND AGE<20;
3)字符串的比较
SQL还提供了根据模式匹配原理比较字符串的能力,其格式是:
s LIKE p
当且仅当字符串s与模式p相匹配时,表达式s LIKE p的值才为真。
当p中含有%时,它可以与s中任何序列的0个或多个字符进行匹
配;
而当p中出现符号“_”时,它可以与s中任何一个字符匹配。
p中的字符只与s中相应位置上的字符匹配 。
例5.12:在表S中找出其姓名中含有“李”的学生。
SELECT *
FROM S
WHERE SNAME LIKE‘%李%‘;
在我们MIS/ERP系统中大都是采用这种模式匹配功能来实现模糊
查询的。
SQL查询语句格式图示
基表名.
列名- 1
视图名.
SELECT
*
DISTINCT
表达式
,
表创建者.
基表名
FROM
别名
视图名
,
条件- 1
WHERE
GROUP BY
列名- 2
,
HAVING
列名- 3
ORDER BY
列序号
ASC
DESC
,
条件- 2
SQL中SELECT语句的格式
SELECT [DISTINCT] <属性列表>
FROM <基本表>(或视图)
[ WHERE <条件表达式>];
[ GROUP BY <分组属性列表> [HAVING <组合条件表达式>]]
[ ORDER BY 排序属性列1[ASC|DESC],…]
整个SELECT语句的执行过程如下:
(1) 读取FROM子句中基本表、视图的数据,执行笛卡儿积操作。
(2) 选取满足WHERE子句中给出的条件表达式的元组。
(3) 按GROUP子句中指定的属性列的值分组,同时提取满足
HAVING子句中组条件表达式的那些元组。
(4)按SELECT子句中给出的属性列或列表达式求值输出。
(5) ORDER子句对输出的结果进行排序,按ASC升序排列或DESC
降序排列。
5.3.4 复杂查询
1)SQL中的笛卡儿积和连接运算
例5.13:查询所有学生的情况以及他们选修课程的课程号和得分。
SELECT S.*,SC.CNO,SC.SCORE
FROM S,SC
WHERE S.SNO=SC.SNO;
其中,WHERE后面的条件称为连接条件或连接谓词。
例5.14:自然连接查询
SELECT S.SNO,S. SNAME,C.CNAME,SC.SCORE
FROM S,C,SC
WHERE S.SNO=SC.SNO AND C.CNO=SC.CNO;
(a)学生关系S
(b)课程关系C
SNO
SNAME
AGE
SEX
DNAME
S1
程宏
19
M
计算机
S3
刘莎莎
18
F
电子
S4
李刚
20
M
自动化
S6
蒋天峰
19
M
电气
S9
王敏
20
F
计算机
CNO
C1
C2
C3
C4
CNAME
计算机基础
C语言
电子学
数据结构
CREDIT
3
3
4
4
PRE_CNO
C1
C1
C2
(c)选课关系SC
(d)自然连接查询的结果表
S.SNO
S.SNAME
C.CNAME
SC.SCORE
S1
程宏
计算机基础
78
S1
程宏
C语言
88
S1
程宏
电子学
76
S1
程宏
数据结构
86
S3
刘莎莎
C语言
64
S3
刘莎莎
电子学
87
S4
李刚
电子学
79
S6
蒋天峰
计算机基础
88
S6
蒋天峰
电子学
68
S9
王敏
C语言
78
S9
王敏
数据结构
83
SNO
CNO
SCORE
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
2)元组变量
表存在自身连接,即查询涉及同一个关系R的两个甚至更多个
元组。
SQL采用的方法是在FROM子句中为R的每一个出现值指定一个
别名(Alias),称之为元组变量(Tuple Variable),其格式是:
FROM <表名> AS <别名>
然后在SELECT和WHERE子句中使用该别名指定属性。
例5.15:在表C中求每一门课程的间接先行课。
SELECT FIRST.CNO,SECOND.PRE_CNO
FROM C AS FIRST,C AS SECOND
WHERE FIRST. PRE_CNO=SECOND.CNO;
元组变量查询事例
(a)FIRST
(b)SECOND
(c)结果表
CNO
PRE_CNO
CNO
PRE_CNO
C1
-
C1
-
CNO
PRE_CNO
C2
C1
C2
C1
C4
C1
C3
C1
C3
C1
C4
C2
C4
C2
本例中的查询实际上是一种推理,即,若用谓词PC(x,y)表示y是x
的先行课程,谓词PPC(x,z)表示z是x的间接先行课,则上述查询
完成的推理可表示为:
xyz( PC(x, y) PC( y, z) PPC(x, z)
3)SQL查询中的并、交、差运算
SQL提供了相应的运算符:UNION, INTERSECT, EXCEPT,分别
对应于集合运算的∪、∩、-(并、交、差)。
(1)并运算的SQL查询语句
例5.16:求选修了课程C2或C4的学生的学号和姓名。
( SELECT S.SNO,S.SNAME
FROM S,SC
WHERE S.SNO = SC.SNO AND CNO='C2')
UNION
( SELECT S.SNO,S.SNAME
FROM S,SC
WHERE S.SNO = SC.SNO AND CNO='C4');
交、差运算SQL
(2)交运算的SQL查询语句
例5.17:求选修了课程C2和C4的学生的学号和姓名。
( SELECT S.SNO,S.SNAME
FROM S,SC
WHERE S.SNO=SC.SNO AND CNO='C2')
INTERSECT
( SELECT S.SNO,S.SNAME
FROM S,SC
WHERE S.SNO=SC.SNO AND CNO='C4');
(3)差运算的SQL查询语句
例5.18:求选修了课程C2但没有选修课程C4的学生的学号和姓名。
( SELECT S.SNO,S.SNAME
FROM S,SC
WHERE S.SNO=SC.SNO AND CNO='C2')
EXCEPT
( SELECT S.SNO,S.SNAME
FROM S,SC
WHERE S.SNO=SC.SNO AND CNO='C4');
查询例子
(a)学生关系S
(c)选课关系SC
SNO
SNAME
AGE
SEX
DNAME
S1
程宏
19
M
计算机
SNO
CNO
SCORE
S3
刘莎莎
18
F
电子
S4
李刚
20
M
自动化
S6
蒋天峰
19
M
电气
S9
王敏
20
F
计算机
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
4)子查询
WHERE子句中的条件表达式可以是标量数据 ,也可以是一个
SELECT-FROM-WHERE查询块构成的子查询。
(1) 产生标量值的子查询
例5.19:求选修了学生S3所选修的课程的那些学生的学号。
SELECT SNO
FROM SC
WHERE CNO=
( SELECT CNO
FROM SC
WHERE SNO='S3');
查询例子
选课关系SC
SNO
CNO
SCORE
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
(2) 包含几个关系的条件
① EXISTS R是一个条件,当且仅当R非空时,该条件为真。
EXISTS相当于离散数学中的存在量词。
② s IN R为真,当且仅当s等于R中的一个值。类似地,s NOT
IN R为真,当且仅当s不等于R中的值。
IN的含义相当于集合论中的“属于”(∈)。类似地,s NOT IN R,
表示s不属于R。
③ s>ALL R为真,当且仅当s大于关系R中的每一个值。同样可
以使用其他五个比较运算符(>=、=、<、<=、<>)。
例如,s<>ALL R,表示s NOT IN R。
④ s>ANY R为真,当且仅当s至少大于关系R中的一个值。同样
可以使用其他五个比较运算符(>=、=、<、<=、<>)。
例如,s = ANY R表示s IN R。
IN查询事例
例5.20:使用运算符IN,求选修了“数据结构”课程的学生的
学号和姓名。
SELECT SNO,SNAME
FROM S
WHERE SNO IN
( SELECT SNO
FROM SC
WHERE CNO IN
( SELECT CNO
FROM C
WHERE CNAME='数据结构'));
(a)学生关系S
查
询
结
果
(b)课程关系C
SNO
SNAME
AGE
SEX
DNAME
CNO
CNAME
DNAME
TNAME
S1
程宏
19
M
计算机
C1
计算机基础
计算机
孙立
S3
刘莎莎
18
F
电子
C2
C语言
计算机
胡恒
S4
李刚
20
M
自动化
C3
电子学
电子
钱敏
S6
蒋天峰
19
M
电气
C4
数据结构
计算机
丁伟
S9
王敏
20
F
计算机
(c)选课关系SC
(d)查询过程与结果
SNO
CNO
SCORE
S3
C3
87
S4
C3
79
S1
C2
88
C.CNO
SC.SNO
S9
C4
83
C4
S9
S1
C3
76
S6
C3
68
S1
C1
78
S6
C1
88
S3
C2
64
S1
C4
86
S9
C2
78
执行III层
结果表
执行II层
S1
S.SNO
S.SNAME
S9
王敏
S1
程宏
EXISTS查询事例
例5.21:使用存在量词EXISTS求选修了C2课程的学生的姓名。
SELECT SNAME
FROM S
WHERE EXISTS
( SELECT *
FROM SC
WHERE S.SNO=SC.SNO AND CNO='C2');
选课关系SC
SNO
CNO
SCORE
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
学生关系S
SNO
SNAME
AGE
SEX
DNAME
S1
程宏
19
M
计算机
S3
刘莎莎
18
F
电子
S4
李刚
20
M
自动化
S6
蒋天峰
19
M
电气
S9
王敏
20
F
计算机
EXISTS查询事例
例5.22:用NOT EXISTS求没有选修C3课程的学生的姓名。
SELECT SNAME
FROM S
WHERE NOT EXISTS
( SELECT *
FROM SC
WHERE S. SNO=SNO AND CNO='C3');
选课关系SC
SNO
CNO
SCORE
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
学生关系S
SNO
SNAME
AGE
SEX
DNAME
S1
程宏
19
M
计算机
S3
刘莎莎
18
F
电子
S4
李刚
20
M
自动化
S6
蒋天峰
19
M
电气
S9
王敏
20
F
计算机
(3)关于全称量词和逻辑蕴涵
在SQL中,通常将带有全称量词的谓词转换为带有存在量词的
谓词:
(x )p(x ) (x(p( x )))
从而利用SQL中WHERE子句的条件表达式中的EXISTS和NOT
EXISTS即可实现该运算。
SQL中也没有蕴涵(Implication)逻辑运算,可以利用下面的等价公
式把蕴涵运算转换为非或运算:
p(x) q(x) p(x) q(x)
逻辑蕴涵事例
例5.23:求至少选修了学生S2所选修的全部课程的学生的学号。
设Cy是学生S2选修课程的集合。如果用p表示谓词“学生S2选
修课程Cy”,q表示谓词“学生Sx选修课程Cy”。
则查询问题可表述为:
(Cy)p q (Cy((p q)))
(Cy((p q))) ((Cy)p q))
SELECT DISTINCT SNO
FROM SC AS SC_A
WHERE NOT EXISTS
( SELECT *
FROM SC AS SC_B
WHERE SC_B. SNO=‘S2' AND NOT EXISTS
( SELECT *
FROM SC AS SC_C
WHERE SC_C.SNO=SC_A.SNO AND SC_C.CNO=SC_B.CNO));
查询条件
SQL可以表达复杂的查询条件,进行多表连接的复杂查询运算。
NOT
项
比较条件
like条件
NULL
表达式
简单条件
between条件
NOT
IS
=
AND
+
¬=
<>
<
<=
( a) 条件
exists条件
( b) 简单条件
简单条件
项
>=
¬>
*
/
¬<
表达式
OR
ALL
in条件
>
-
( d) 表达式
(
ANY
SOME
( c) 比较条件
子查询块
)
查询条件
USER
基表名.
AVG
视图名.
DATE
列名
+
-
(
MAX
常量
MIN
特殊常量
CURRENT
SUM
表达式
标量函数
聚集函数
( e) 项
日期、DISTINCT
时间函数
)
列名
TIME
数字、 字符函数
(
)
TIMESTAMP
*
( g)
标量函数
(
COUNT
列名
TIMEZONE
DISTINCT
( f) 特殊常量
( h) 聚集函数
)
查询条件
表达式
比较条件
BETWEEN
表达式
AND
表达式
NOT
( i) between条件
between条件
表达式
字符串
'
LIKE
'
NOT
like条件
( j) like条件
子查询块
in条件
表达式
exists条件
IN
常量
(
)
,
NOT
( k) in条件
( b) 简单条件
EXISTS
(
NOT
( l) exists条件
子查询块
)
5.4 聚集函数(Aggregation)
5.4.1 聚集函数的运算符
5.4.2 数据分组
5.4.3 数据排序
5.4.1 聚集函数的运算符
AVG
DISTINCT
SQL提供了下列的聚集函数:
AVG(属性列),求某列上值的平均值。
MAX
列名
(
)
MIN
SUM
MAX(属性列),求某列值中的最大值。 COUNT
MIN(属性列),求某列值中的最小值。
SUM(属性列),求某一列上值的总和。
*
(
列名
)
DISTINCT
聚集函数
COUNT(*),计算元组的个数。
COUNT(属性列),计算某列值中的个数。
注意,除非使用DISTINCT,否则,重复元组的个数也计算在内。
学生关系S
聚集函数事例
SNO
S1
S3
S4
S6
S9
SNAME
程宏
刘莎莎
李刚
蒋天峰
王敏
例5.25:求学生总人数。
SELECT COUNT(*)
FROM S;
例5.26:求选修了课程学生的人数。
SELECT COUNT (DISTINCT SNO)
FROM SC;
例5.27:求平均分数。
SELECT AVG(SCORE)
FROM SC;
例:列出所有课程的最高成绩、最低成绩;
SELECT MAX(SCORE),MIN(SCORE)
FROM SC
AGE
19
18
20
19
20
SEX
M
F
M
M
F
DNAME
计算机
电子
自动化
电气
计算机
选课关系SC
SNO
CNO
SCORE
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
5.4.2 数据分组
1)GROUP BY子句
GROUP BY子句将表按列值进行分组,列的值相同的分在一组。
为了对一个关系中元组进行分组,在WHERE或FROM子句后增加:
选课关系SC
GROUP BY<属性名表>
例5.28:求已选修的课程号及其选修该课程的
学生人数。
SELECT CNO,COUNT(SNO)
FROM SC
GROUP BY CNO;
SNO
CNO
SCORE
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
数据分组执行步骤
一个分组功能可能涉及几个关系的查询,按下列步骤进行:
(1) 求出FROM子句和WHERE子句蕴涵的关系R,即关系R是FROM子
句中关系的笛卡儿积,再对这个关系应用WHERE子句中的条件
进行选择。
(2) 按照GROUP BY子句中的属性对R中的元组进行分组。
(3) 根据SELECT子句中的属性和聚集产生结果。
例5.29:对计算机系的学生按课程列出选修了该课程的学生的人数。
SELECT CNO,COUNT(SC.SNO)
FROM S,SC
WHERE S.DNAME='计算机' AND S.SNO=SC.SNO
GROUP BY CNO;
选课关系SC
数据分组查询事例
学生关系S
SNO
S1
S3
S4
S6
S9
S╳SC
SNAME
程宏
刘莎莎
李刚
蒋天峰
王敏
S.SNO
S1
S1
S1
S1
…
S3
S3
S4
…
S6
S6
…
S9
S9
…
AGE
19
18
20
19
20
S.SNAME
程宏
程宏
程宏
程宏
…
刘莎莎
刘莎莎
李刚
…
蒋天峰
蒋天峰
…
王敏
王敏
…
SEX
M
F
M
M
F
S.AGE
19
19
19
19
…
18
18
20
…
19
19
…
20
20
…
DNAME
计算机
电子
自动化
电气
计算机
S.SEX
M
M
M
M
…
F
F
M
…
M
M
…
F
F
…
S.DNAME
计算机
计算机
计算机
计算机
…
电子
电子
自动化
…
电气
电气
…
计算机
计算机
…
SNO
CNO
SCORE
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
SC.SNO
S1
S1
S1
S1
…
S3
S3
S4
…
S6
S6
…
S9
S9
…
SC.CNO
C1
C2
C3
C4
…
C2
C3
C3
…
C1
C3
…
C2
C4
…
SC.SCORE
78
88
76
86
…
64
87
79
…
88
68
…
78
83
…
2)HAVING子句
如果我们在分组的基础上进一步希望只选出满足条件的分组。
SQL解决这个问题的方法是,在GROUP BY子句后面跟以一个
HAVING子句,描述分组的条件。其格式为:
选课关系SC
HAVING <条件>
SNO
CNO
SCORE
例5.30:求选修课程超过3门的学生的学号。
SELECT SNO
FROM SC
GROUP BY SNO
HAVING COUNT (*)>3;
S1
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C1
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
78
88
76
86
64
87
79
88
68
78
83
5.4.3 数据排序
ORDER BY 子句可对查询结果按子句中指定的属性列的值排序,
其基本格式是在WHERE子句后增加:
ORDER BY <属性1> [ASC|DESC] [,<属性2> [ASC|DESC]…]
例如:按学生S1各门课程的成绩由高到低进行显示。
选课关系SC
SELECT CNO, SCORE
SNO
CNO
FROM SC
S1
C1
WHERE SNO=‘S1'
S1
C2
S1
C3
ORDER BY SCORE DESC;
S1
C4
S3
S3
S4
S6
S6
S9
S9
C2
C3
C3
C1
C3
C2
C4
SCORE
78
88
76
86
64
87
79
88
68
78
83
数据排序(事例2)
例5.31:试列出各门课程的最高成绩、最低成绩和平均成绩,
结果按课程号排序。
SELECT CNO, MAX(SCORE),MIN(SCORE),AVG(SCORE)
FROM SC
选课关系SC
GROUP BY CNO
SNO
CNO
SCORE
S1
C1
78
ORDER BY CNO;
S1
S1
S1
S3
S3
S4
S6
S6
S9
S9
C2
C3
C4
C2
C3
C3
C1
C3
C2
C4
88
76
86
64
87
79
88
68
78
83
5.5 数据库更新
SQL提供的数据库修改操作主要有元组插入、删除和修改。
表名
INSERT INTO
列名
(
)
,
VALUES
(
数据项
表名
UPDATE
)
表创建者.
,
查询语句
SET
( a) INSERT语句
表名
DELETE FROM
表创建者.
( b) DELETE语句
WHERE
条件
列名= 表达式
,
( c) UPDATE语句
WHERE
条件
5.5.1 元组插入
元组插入语句的一般格式是:
INSERT INTO <表名>[ (<属性名1> [,<属性名2>,…])]
VALUES (<常量1> [,<常量2>,…]);
或者 INSERT INTO <表名>[ (<属性名1> [,<属性名2>,…])]
<子查询>;
例5.32:往关系S中插入记录(' S10 ' , '李四')
INSERT INTO S(SNO,SNAME) VALUES(‘S10’,‘李四’);
例5.33:往关系SC中插入选课记录('S10','C4 ' ,80)
INSERT INTO SC(SNO,CNO,SCORE) VALUES('S10 ','C4 ',80);
INSERT子查询事例
例5.34:把到目前为止还没有选修课程的学生的学号插入关系SC中。
INSERT INTO SC(SNO)
SELECT SNO
FROM S
WHERE SNO NOT IN
( SELECT DISTINCT SNO
FROM SC);
5.5.2 元组删除
删除元组的语句格式是:
DELETE
FROM <表名>
[WHERE <条件>];
例5.35:从关系s中把学生S10删除。
DELETE
FROM S
WHERE SNO='S10';
删除计算机系全体学生的选课记录。
DELETE
FROM SC
WHERE '计算机'=
( SELECT DNAME
FROM S
WHERE S.SNO=SC.SNO);
事例 (S、C、SC数据删除与插入)
delete from S;
insert into S(SNO,SNAME,AGE,SEX,DNAME) values ('S1','程宏',19,'M','计算机');
insert into S(SNO,SNAME,AGE,SEX,DNAME) values ('S3','刘莎莎',18,'F','电子');
insert into S(SNO,SNAME,AGE,SEX,DNAME) values ('S4','李刚',20,'M','自动化');
insert into S(SNO,SNAME,AGE,SEX,DNAME) values ('S6','蒋天峰',19,'M','电气');
insert into S(SNO,SNAME,AGE,SEX,DNAME) values ('S9','王敏',20,'F','计算机');
delete from C;
insert into C(CNO,CNAME,CREDIT,PRE_CNO) values ('C1','计算机基础',3,' ');
insert into C(CNO,CNAME,CREDIT,PRE_CNO) values ('C2','C语言',3,'C1');
insert into C(CNO,CNAME,CREDIT,PRE_CNO) values ('C3','电子学',4,'C1');
insert into C(CNO,CNAME,CREDIT,PRE_CNO) values ('C4','数据结构',4,'C2');
delete from SC;
insert into SC(SNO,CNO,SCORE) values ('S3','C3', 87);
insert into SC(SNO,CNO,SCORE) values ('S4', 'C3', 79);
insert into SC(SNO,CNO,SCORE) values ('S1', 'C2', 88);
insert into SC(SNO,CNO,SCORE) values ('S9', 'C4', 83);
insert into SC(SNO,CNO,SCORE) values ('S1', 'C3', 76);
insert into SC(SNO,CNO,SCORE) values ('S6', 'C3', 68);
……
5.5.3 元组修改
SQL中用数据修改(UPDATE)来修改元组的值。其语句格式是:
UPDATE <表名>
SET <属性1>=<表达式1>[,<属性2>=<表达式2>,…]
[WHERE <条件>];
例5.36:把所有学生的年龄加1。
UPDATE S
SET AGE=AGE+1;
例5.37:将计算机系所有学生的成绩置零。
UPDATE SC
SET SCORE=0
WHERE '计算机'=
( SELECT DNAME
FROM S
WHERE SC.SNO=S.SNO);
避免参照完整性错误
如果修改操作涉及多个表,则可能破坏参照完整性。
例5.38:若把学号S9改为S2,
UPDATE S
SET SNO='S2'
WHERE SNO='S9';
UPDATE SC
SET SNO='S2'
WHERE SNO='S9';
为了解决这个问题,唯一的办法是保证这些修改操作作为一个
整体,或者全部完成,或者全部不执行。
许多数据库引入事务(Transaction)概念来解决这个问题。
5.6 视图
5.6.1 视图定义
5.6.2 视图查询
5.6.3 视图更新
5.6.4 视图删除
5.6.5 视图的作用
5.6.1 视图定义
SQL中视图定义的语句格式为:
CREATE VIEW <视图名> [(<属性名1>[,<属性名2>,…])]
AS<子查询>
[WITH CHECK OPTION];
AS
查询语句
视图名
CREATE VIEW
例5.39:建立计算机系学生的视图。
(
)
列名
CREATE VIEW CS_VIEW
AS SELECT *
,
FROM S
WHERE DNAME=‘计算机’
学生关系S
例5.40:定义一个视图,使之包括学生的学号及其各门功课的平
SNO
SNAME
AGE
SEX
DNAME
均成绩。
19
M
程宏
计算机
CREATE VIEW S_G_ S1
VIEW
(SNO,GAVG)
S3
18
F
刘莎莎
电子
AS SELECT SNO,AVG(SCORE)
S4
20
M
李刚
自动化
FROM SC
S6
19
M
蒋天峰
电气
20
F
GROUP BY SNO S9
王敏
计算机
5.6.2 视图查询
视图一经定义,用户就可以如同基本表那样对它进行查询。
例5.41:对例5-39中的视图CS_VIEW,找出年龄小于20的那些学生。
SELECT *
FROM CS_ VIEW
WHERE AGE<20;
执行该视图查询时,首先把它转换成对基本表S的查询,即:
SELECT *
FROM S
WHERE DNAME= '计算机' AND AGE<20;
视图查询事例2
例如,对在例5-40的S_G_VIEW视图上,求平均成绩为80分以上
的学生的学号和成绩:
SELECT *
FROM S_G_VIEW
WHERE GAVG>=80;
不正确的查询转换为:
SELECT SNO,AVG(SCORE)
FROM SC
WHERE AVG(SCORE)>=80
GROUP BY SNO;
正确的转换应为:
SELECT SNO, AVG(SCORE)
FROM SC
GROUP BY SNO
HAVING AVG(SCORE)>=80;
5.6.3 视图更新
对于某些非常简单的视图,即由一个基本表定义的视图,只含有
基本表的主键或候补键,并且视图中没有用表达式或函数定义的
属性,在把对视图的更新操作可以转换为对基本表的等价操作。
例 5.42 : 在 例 5-39 的 视 图 CS_VIEW 上 , 将 学 生 S1 的 姓 名 改 为
“WU PING”:
UPDATE CS_VIEW
SET SNAME='WU PING'
WHERE SNO='S1';
执行该修改时首先将它转换成对基本表S的更新:
UPDATE S
SET SNAME='WU PING'
WHERE DNAME='计算机' AND SNO='S1';
不可更新视图
并非对所有视图都能这样做,就是说,有些视图上的更新不能
转换成对其基本表的等价操作。
例如,下列视图是不可更新的。
对例5.40中的视图S_G_VIEW,将学号为S1的学生的平均成绩改
为90分:
UPDATE S_G_VIEW
SET GAVG=90
WHERE SNO='S1';
由于视图S_G_VIEW中的一个元组是由基本表SC中若干元组经
过分组再求平均得到的,所以,对视图S_G_VIEW的更新就无法
转换成对SC的等价的更新操作,可见,该视图是不可更新的。
视图更新限制
目前,关系系统只提供对行列子集视图的更新,并有以下限制:
若视图的 属性来自 属性表达 式或常数 ,则不允 许对视图 执行
INSERT和UPDATE操作,但允许执行DELETE操作。
若视图的属性来自库函数,则不允许对此视图更新。
若视图定义中有GROUP BY子句,则不允许对此视图更新。
若视图定义中有DISTINCT任选项,则不允许对此视图更新。
若视图定义中有嵌套查询,并且嵌套查询的FROM子句涉及导出
该视图的基本表,则不允许对此视图更新。
若视图由多表连接所定义的视图,则不允许对此视图更新。
如果在一个不允许更新的视图上再定义一个视图,这种二次视图
是不允许更新的。
5.6.4 视图删除
视图删除也是一种视图更新,但是,一个视图不管是否可更
新,都可以删除它。其语句格式是:
DROP VIEW <视图名>;
这条语句删去了一个视图的定义,与该视图有关的操作就不
能再执行了。如果执行语句
DROP TABLE <表名>;
不仅删去了指定的基本表,而且也使与它有关的视图不可用。
5.6.5 视图的作用
1)视图为重新构造(简称重构)数据库提供了一定程度的逻辑独立性。
把关系模式
S (SNO,SNAME,AGE,DNAME)
分为两个子表:
STU_1(SNO,SNAME,AGE)
STU_2 (SNO,DNAME)
显然,原表STU是两个子表STU_1和STU_2的自然连接。用户同样可以建
立一个如同原表一样的视图:
CREATE VIEW S(SNO,SNAME,AGE,DNAME)
AS SELECT STU_1.SNO,STU_1.SNAME,STU_1.AGE,STU_2.DNAME
FROM STU_1,STU_2
WHERE STU_1.SNO=STU_2.SNO;
2)聚焦用户数据
3)视图机制允许不同用户以不同的观点或方式看待同一数据。
4)视图可以作为机密数据的自动安全机制。
5.7 嵌入式SQL
5.7.1 程序设计环境下的SQL
宿主语言+嵌入式SQL
预处理器
宿主语言+函数调用
宿主语言编译器
宿主语言程序
SQL函数库
1)宿主语言中嵌入SQL须解决的问题
(1)宿主语言编译器不可能识别和接受SQL语言,如何将嵌入有
SQL的宿主语言程序编译成可执行码,这是首先要解决和问题。
(2)宿主语言和DBMS之间如何传递数据和信息。
(3)数据库的查询结果一般是元组的集合,这些元组须逐个地赋
值给宿主语言程序中的变量,供其处理,其间还存在一个转换
问题。
(4)两者的数据类型有时不完全对应或等价,须解决必要的数据
类型转换问题。
2)SQL与宿主语言之间的接口
为了能够在只能由SQL语句访问的数据库与宿主语言程序之间
传递信息,利用也能被SQL读写的宿主语言变量作为桥梁,称
为共享变量或称宿主变量。
3)共享变量的说明和使用
共享变量说明节定义的格式为:
EXEC SQL BEGIN DECALRE SECTION;
<共享变量定义>
EXEC SQL END DECLARE SECTION;
例5.44:按C语言类型定义方式说明共享变量。
EXEC SQL BEGIN DECALRE SECTION;
CHAR s#[6],sn[8],sd[36];
INT sa;
EXEC SQL END DECLARE SECTION;
SQL语句的C语言函数
例5.44:由宿主语言将有关数据读入共享变量,然后由SQL插入
数据库S(SNO,SNAME,AGE,DNAME)。
Void getstu(){
(1)EXEC SQL BEGIN DECALRE SECTION;
(2) CHAR s#[6],sn[8],sd[36];
(3) INT sa;
(4) CHAR SQLSTATE[6];
(5)EXEC SQL END DECLARE SECTION;
{……}
/*由宿主语言将学号、姓名、年龄和所在系读入共享变量s # ,sn,sa和
sd*/
(6)EXEC SQL INSERT INTO S(SNO,SNAME,AGE,DNAME)
(7)VALUES(:s#,:sn,:sa,:sd);
{……}
}
共享变量出现的位置
SELECT语句的INTO子句中(表示将检索结果存放到共享变
量中);
SELECT, UPDATE, DELETE语句的WHERE子句中,表示由
宿主语言程序传递的条件信息;
UPDATE的SET子句中,表示由宿主语言传递的数据;
INSERT语句VALUES子句中,也表示由宿主语言传递的数据;
作为SELECT,WHERE或SET(不含VALUES子句)中的算术表
达式元素。
嵌入式SQL还使用下列机制把查询结果与宿主语言联系起来:
(1)使用多个共享变量把查询结果送往宿主语言。
(2)使用游标(Cursor)。
5.7.2 单行选择语句
例5.45:下面的C语言函数用于从关系SC中读取给定学号和课程号
的分数,并送宿主语言处理。
Void PrintGrade(){
(1) EXEC SQL BEGIN DECALRE SECTION;
(2) CHAR s#[6],c#[4];
(3) INT g;
(4) CHAR SQLSTATE[6];
(5) EXEC SQL END DECLARE SECTION;
{……}
/*由宿主语言读入学号、课程号到共享变量s#,c#*/
(6) EXEC SQL SELECT SCORE
(7)
INTO:g
(8)
FROM SC
(9)
WHERE SNO=:s#AND CNO=:c#;
{……}
}
例5.46:设有关系模式
EMP (ENO,ENAME,ESEX,EAGE,SALARY,DNO)
下面的C语言函数用于将共享变量e#指定的职工的工资增加由共
享变量raise给定的数额。
Void Raise_Salary(){
(1) EXEC SQL BEGIN DECALRE SECTION;
(2)
CHAR e#[6];
(3)
INT raise;
(4)
CHAR SQLSTATE[6];
(5) EXEC SQL END DECLARE SECTION;
{……}
/*由宿主语言读入工号、增加的工资数额raise*/
(6) EXEC SQL UPDATE EMP
(7)
SET SALARY=SALARY+:raise
(8)
WHERE ENO=:e#;
}
5.7.3 游标
1)游标的定义和使用
(1)游标说明
EXEC SQL DECALRE<游标名>CURSOR FOR(SELECT查询块);
(2)打开游标
EXEC SQL OPEN <游标名>;
(3)取数语句
EXEC SQL FETCH <游标名> INTO <共享变量列表>;
(4)关闭游标
EXEC SQL CLOSE <游标名>;
例5.47:设有关系模式
EMP (ENO,ENAME,ESEX,EAGE,SALARY,DNO)
下面的C语言函数用于将指定部门每个职工的工资增加若干元。
Void Add-Salary(){
(1) EXEC SQL BEGIN DECLARE SECTION;
(2)
CHAR dept#[21;
(3)
REAL money,raise;
(4)
CHAR SQLSTATE[6];
(5) EXEC SQL END DECLARE SECTION;
{……}
/*由C语言读入部门号以及增加的工资数额,分另明存放在共享变量dept#和
raise中*/
(6) EXEC SQL DECLARE SalaryCursor CURSOR FOR
(7)
SELECT SALARY
(8)
FROM EMP
(9)
WHERE DNO=:dept#;
(10) EXEC SQL OPEN SalaryCursor;
(11) EXEC SQL FETCH SalaryCursor INTO:money;
(12) while (NO_MORE_TUPLES)
(13)
EXEC SQL UPDATE EMP
(14)
SET SALARY=:money+:raise
WHERE CURRENT OF SalaryCursor;
(15) EXEC SQL CLOSE SalaryCursor;
}
2)游标的控制和选择
(1)控制结果关系中元组的排列次序
例5.48:设有关系模式
EMP(ENO,ENAME,BIRTHRATE,DNAME)
下面是一个使用ORDER BY子句控制取元组次序的游标说明语句:
(1)EXEC SQL DECLARE BirthdateCursor CURSOR FOR
(2)
SELECT ENAME,BIRTHRATE
(3)
FROM EMP
(4)
WHERE DNAME='SALES'
(5)
ORDER BY BIRTHRATE,DNAME;
(2)保护当前的更新
EXEC SQL DECLARE INSENSITIVE BirthdateCursor CURSOR FOR
(3)滚动游标
第 一 , 在 说 明 游 标 时 , 在 保 留 字 CURSOR 前 加 上 保 留 字
SCROLL 。
第二,在FETCH语句中,在保留字 FETCH后面加上关于找到
所希望的元组位置的选择。
这些选择是:
NEXT或PRIOR,表示要得到游标当前位置的下一个或前一个
元组。
FIRST或LAST,表示要得到该次序中的第一个或最后一个元组。
RELATIVE <正整数或负整数>,表示要得到游标当前位置向前
(负整数)或向后(正整数)移动若干个元组。
ABSOLUTE<正整数或负整数>,表示从结果关系的前面(负整
数)或从后面(正整数)计算所要元组的位置。
本章小结
SQL是关系数据库的标准语言,已广泛应用在商用系统中。
SQL的数据定义部分包括对SQL模式、基本表、视图、索引
的创建和撤消。
SQL的数据操纵分成数据查询和数据更新两部分。
SQL的数据查询是用SELECT语句实现,兼有关系代数和元
组演算的特点。
SQL的数据更新包括插入、删除和修改等三种操作,在视图
中只有行列子集视图是可以更新的。
嵌入式SQL涉及到SQL语句的宿主语言程序中的使用规定,
以解决两种语言的不一致和相互联系的问题。
重要内容分析 (1)
SELECT语句是SQL的核心内容,对于该语句应掌握
下列内容。
1)SELECT语句的来历
在关系代数中最常用的式子是下列表达式:
πA1, … ,An(σF(R1×…×Rm))
针对上述表达式,SQL为此设计了SELECT-FROM-WHERE句型:
SELECT A1,…,An
FROM R1,…,Rm
WHERE F;
2)SELECT语句中出现的基本表名,应理解为基本表中的元组变
量,而列名应理解为元组分量。
重要内容分析 (2)
3)SELECT语句的语义有三种情况,下面以学生表S(SNO,
SNAME,AGE,SEX)为例说明。
第一种情况:SELECT语句中未使用分组子句,也未使用聚合操
作,那么SELECT子句的语义是对查询的结果执行投影操作。譬
如:
SELECT SNO,SNAME
FROM S
WHERE SEX='M';
第二种情况:SELECT语句中未使用分组子句,但在SELECT子
句中使用了聚合操作,此时SELECT子句的语义是对查询结果执
行聚合操作。譬如:
SELECT COUNT(*),AVG(AGE)
FROM S
WHERE SEX='M';
该语句是求男同学的人数和平均年龄。
重要内容分析 (3)
第三种情况:SELECT语句使用了分组子句和聚合操作(有分
组子句时必有聚合操作),此时SELECT子句的语义是对查询
结果的每一分组去做聚合操作。譬如:
SELECT AGE,COUNT(*)
FROM S
WHERE SEX='M'
GROUP BY AGE;
该语句是求男同学每一年龄的人数。
4)SELECT语句中使用分组子句的先决条件是要有聚合操作。
但执行聚合操作不一定要用分组子句。譬如求M同学的人数,此
时聚合值只有一个,因此不必分组。
但同一个聚合操作的值有多个时,必须使用分组子句。譬如
求每一年龄的学生人数。此时聚合值有多个,与年龄有关,因此
必须分组。