第三章 关系数据库标准语言SQL (8-10学时) 数据库原理和语言 第三章 关系数据库标准语言SQL (8-10学时) 2005年8月6日 主讲:曹志英 副教授 大连海事大学计算机科学与技术学院 研究方向:软件工程与理论•数据库与信息系统 电话:84729625 Email:czy_sophy@163.com
引 言 SQL= Structured Query Language SQL是一种介于关系代数与关系演算之间的结构化查询语言,其功能: 引 言 SQL= Structured Query Language SQL是一种介于关系代数与关系演算之间的结构化查询语言,其功能: 不仅仅是查询; 还是一个通用的、功能极强的关系数据库语言。 数据定义(DDL) 数据查询(Data Query) 数据操纵(DML) 数据更新(Data Update) 数据控制(DCL)
目录 §3.1 SQL语言的基本概念与特点(P84-P87) §3.2 数据定义(P87-P91) §3.3 查询(P91-P116)
3.1 SQL语言的基本概念与特点 3.1.1 SQL语言的发展及标准化 3.1.2 SQL语言的特点 3.1.3 SQL语言的基本概念
3.1.1 SQL语言的发展及标准化 SQL(Structured Query Language):是关系数据库标准语言。 u1974年:Boyce和Chamberlin提出。 u1975~1979年:IBM公司San Jose Research Laboratory研制了System R(DBMS原型),实现了这种语言。 u1986年10月,SQL经美国国家标准局批准成为关系数据库语言的美国国家标准。同年公布SQL的标准文本SQL-86。 u1987年,ISO通过了这一标准,后经ANSI修改和完善,逐步发布SQL-89,SQL-92,SQL-99。 SQL语言现已成为数据领域的一个主流语言。
3.1.2 SQL语言的特点 集数据定义、数据查询、数据操纵、数据控制于一体。 综合统一 高度非过程化语言 面向集合的操作方式 以同一种语法结构提供两种使用方式 自 含式语言:联机交互的使用方式 嵌入式语言:嵌入高级语言如C,COBOL,FORTRAN,PB等 语言简洁,易学易用
SQL语言的动词 SQL功能 动词 数据查询 SELECT 数据定义 CREATE、DROP、ALTER 数据更新 INSERT、DELETE、UPDATE 数据控制 GRANT、REVOKE
3.1.3 SQL语言的基本概念 基本表(BASE TABLE):是独立存在的表,一个关系对应一个基本表,一个或多个基本表对应一个存储文件,一个表可带若干个索引。 存储文件的逻辑结构组成了关系数据库的内模式,物理结构是任意的,对用户透明。 视图(VIEW):是一个虚拟的表,是从一个或几个基本表导出的表。它本身不独立存在于数据库中,数据库中只存放视图的定义而不存放视图对应的数据,这些数据仍存放在导出视图的基本表中。当基本表中的数据发生变化时,从视图中查询出来的数据也随之改变。 外模式对应于视图和部分基本表,模式对应于基本表,内模式对应于存储文件。
图3.1 SQL语言支持的关系数据库的三级逻辑结构(P87) 引用返回 视图2 存储文件2 视图1 基本表1 基本表2 基本表3 基本表4 存储文件1 SQL 外模式 模式 内模式 数据流(Data) 元数据流(Meta Data) 数据词典 (元数据) 图3.1 SQL语言支持的关系数据库的三级逻辑结构(P87)
§3.2 数据定义(P87-P91) § 3.2.0 概述 § 3.2.1 字段数据类型 § 3.2.2 创建、修改和删除数据表 § 3.2.0 概述 § 3.2.1 字段数据类型 § 3.2.2 创建、修改和删除数据表 § 3.2.3 设计、创建和维护索引
§3. 2. 0 概述 SQL数据定义功能,支持三级模式: §3. 2. 0 概述 SQL数据定义功能,支持三级模式: 即包括对基本表、视图、索引的定义功能。 由于视图是依赖基本表的“虚表”,索引依附于基本表。所以 SQL通常不提供对视图的修改,以及索引的修改功能。要想修改视图定义或索引定义只能先将它删除掉,然后再重建。不过有的DBMS支持视图的修改。 SQL数据定义语句 DROP INDEX CREATE INDEX 索引 DROP VIEW CREATE VIEW 视图 ALTER TABLE DROP TABLE CREATE TABLE 表 操作方式 创建 删除 修改 操作对象
§ 3.2.1 字段数据类型 SQL语句的数据类型应DBMS的不同而有所差异,常用的数据类型有: 字符型: § 3.2.1 字段数据类型 SQL语句的数据类型应DBMS的不同而有所差异,常用的数据类型有: 字符型: char(n) 、varchar(n) 数值型: integer(n) 全字长二进制整数 smallint(n)、tinyint(n) 半字长二进制整数 decimal(p,d)、numeric(p,d) 压缩十进制数 日期/时间型:date(yyyy-mm-dd) time(hh:mm:ss) timestamp(日期加时间)
§ 3.2.2 创建、修改和删除数据表 3.2.2.1 创建数据表 3.2.2.2 修改基本表 3.2.2.3 删除基本表
3.2.2.1 创建基本表 1. 基本表是关系数据库的基本组成单位,它物理地存储于数据库的文件中。 2. 创建基本表的SQL语法格式 3.2.2.1 创建基本表 1. 基本表是关系数据库的基本组成单位,它物理地存储于数据库的文件中。 2. 创建基本表的SQL语法格式 CREATE TABLE <表名> (<列名><数据类型>[列级完整性约束条件] [,<列名> <数据类型>[列级完整性约束条件]]… [,表级完整性约束条件]); 3. 注意: 表名是所要定义的基本表的名称,必须是合法标识符。 列名是每个表所含的属性(字段名)。一个表有多个属性。 定义各个列/属性时要指明其数据类型。 对列定义最基本要求:类型,长度,能否为空值。 关键字的大写(大小写无所谓,但为区别,作为习惯最好大写),语句的分号结束 。
(Sno Char(5) Not NULL UNIQUE, Sname Char(20) UNIQUE, Ssex Char(2) , 例1: 建立一个“学生表”Student,它由学号(Sno),姓名(Sname),性别(Ssex),年龄(Sage)所在系(Sdept)五个属性组成,其中学号不能为空:且姓名取值也唯一。(P88) CREATE TABLE Student (Sno Char(5) Not NULL UNIQUE, Sname Char(20) UNIQUE, Ssex Char(2) , Sage Int, Sdept Char(15)); 对于不同的DBMS,所支持到的类型不完全相同,建表时参照系统手册。 注意: 表名必须是合法标识符 定义各个属性时要指明其数据类型
再例: 创建课程( course )表: 创建选课( sc )表: Create table course ( cno char(2) primary key, cname char(40) unique, ccredit integer, ctime int, ); 创建选课( sc )表: Create table sc cno char(2), sno char(5) , grade single
[ CONSTRAINT <约束名> ] <约束类型> 注意:若不指定约束名,系统会自动取名 4. 定义完整性约束 基本语法格式: [ CONSTRAINT <约束名> ] <约束类型> 注意:若不指定约束名,系统会自动取名 对于基本表的约束分为列约束和表约束: 列约束是对某一个特定列的约束,包含在列定义中,直接跟在该列的其他定义之后,用空格分隔,不必指定列名; 表约束与列定义相互独立,不包括在列定义中。通常用于对多个列一起进行约束,与列定义用’,’分隔。 定义表约束时,必须指出要约束的那些列的名称。
约束的命名 属性约束 元组约束 主码约束 参照约束 Name char(10) Constraint NameIsKey primary Key 元组约束 Constraint RightTitle Check(gender = ‘F’ OR name Not Like ‘Ms.%’) 主码约束 …… Constraint pk_stu Primary Key (sno), 参照约束 Constraint fk_sc_stu Foreign Key (sno) References student(sno),
约束的类型与实例* (1)PRIMARY KEY约束 (2)NULL/NOT NULL约束 (3)UNIQUE约束 (4) CHECK完整性约束 (5) FOREIGN KEY约束 (6)DEFAULT 约束 (7)PRIMARY KEY与UNIQUE
(1)PRIMARY KEY约束 定义主键,起唯一标识作用,其值不能为NULL,也不能重复 用于定义列约束时: [CONSTRAINT <约束名> ] PRIMARY KEY Create Table MovieStar ( name char(30) Primary Key, address Varchar(255), gender char(1), birthday Date ); Create Table MovieStar ( name char(30) constraint pk_name Primary Key, address Varchar(255), gender char(1), birthday Date );
用于定义表约束时,即将某些列的组合定义为主键: [CONSTRAINT <约束名>] PRIMARY KEY (<列名>[, <列名>…]) Create Table MovieStar ( name char(30), address Varchar(255), gender char(1), birthday Date, Primary Key(name) ); Create Table Movie ( title char(20), name char(30), year integer, incolor boolean, studioname char(20), producerC# integer, constraint pk_tn Primary Key(title,name) );
Primary Key约束:隐含Not Null (2)NULL/NOT NULL约束 只能用于定义列约束 [CONSTRAINT <约束名> ] [NULL|NOT NULL] 在定义属性时,约束该属性不可取Null Sname char(20) not null 不加约束:隐含允许Null Primary Key约束:隐含Not Null
(3)UNIQUE约束 UNIQUE约束用于指明基本表在某一列或多个列的组合上的取值必须唯一 定义列约束: 定义表约束: [CONSTRAINT <约束名>] UNIQUE 定义表约束: [CONSTRAINT <约束名>] UNIQUE(<列名>[{,<列名>…}]) Create Table MovieStar ( name char(30) Primary Key, ID char(18) Unique, address Varchar(255), gender char(1), birthday Date ); Create Table MovieStar ( name char(30), ID char(18), address Varchar(255), gender char(1), birthday Date, Primary Key (name), Unique (ID) );
CHECK约束用来检查字段值所允许的范围 表约束与列约束语法格式为: [CONSTRAINT <约束名>] CHECK (<条件>) 列级约束: 在定义属性时约束该属性必须使Check 中的条件为True 表级约束:存在于关系定义中的Check 对关系中的当前元组的约束 不适于多关系、子查询
【例】 建立考生登记表, 要求考号非空且惟一, 年龄小于65, 性别只能是“男”或“女”, 姓名非空。 CREATE TABLE Examinee (Eno CHAR(14), Ename CHAR(10) NOT NULL, Eage INT CONSTRAINT Y1 CHECK(Eage<65), Esex CHAR(2) CONSTRAINT Y2 CHECK(Esex IN(′男′, ′女′)), PRIMARY KEY(Eno));
【例】建立考生成绩登记表, 要求各科成绩之和<=800 。 CREATE TABLE Exgrade ( Eno CHAR(14), Composition DECIMAL(4, 2), Math DECIMAL(4, 2), English DECIMAL(4, 2), Synthesis DECIMAL(4, 2), CONSTRAINT YS1 CHECK (Composition+Math+English+Synthesis<=800));
FOREIGN KEY约束指定某一个列或一组列作为外部键,其中: 包含外部键的表,称为从表; 包含外部键所引用的主键或唯一键的表,称主表。 系统保证从表在外部键上的取值要么是主表中某一个主键值或唯一键值,要么取空值。以此保证两个表之间的连接,确保了实体的参照完整性。
定义列约束: 属性级/列级: [CONSTRAINT <约束名>] REFERENCES <主表名> (<列名>) 属性级/列级: Create table sc ( Cno char(2) constraint fk_cno references course(cno), Sno char(5) constraint fk_sno references students(sno), grade single );
定义表约束: 实例 [CONSTRAINT <约束名>] FOREIGN KEY (<列名>[{<列名>…}]) REFERENCES <主表名> (<列名>[{<列名>…}]) 实例 Create table sc ( cno char(2), sno char(5) , grade single , constraint fk_sno foreign key (sno) references students(sno), constraint fk_cno foreign key (cno) references course(cno) );
(6)DEFAULT 约束 如果用户在插入新行时没有显示为列提供数据,系统将默认值赋给该列 只能用于定义列约束 语法格式: [CONSTRAINT <约束名> ] DEFAULT 表达式 实例: Create table Dynamic_data (ModifyDate char(30) Default TimeStamp, d_value integer); Alter Table students Add ID integer Default AutoIncrement;
PRIMARY KEY与UNIQUE约束类似,通过建立唯一索引来保证基本表在主键列取值的唯一性,但它们之间存在着很大的区别: 注意:不能为同一个列或一组列既定义UNIQUE约束,又定义PRIMARY KEY约束。
练习: 1)创建表cars(model_no,brand,make,style,year,description),其中:model_no是主键,brand非空。 2)创建表parts(part_no,name,description),其中: part_no是主键,name要求唯一。 3)创建表car_parts(model_no,part_no,qty_req),其中:model_no+part_no是主键, model_no是外键(被参照文件是cars), part_no是外键(被参照文件是parts) 。 3)create table car_parts ( model_no char(10), part_no char(12), qty_reg int constraint pk_mp primary key(model_no,part_no), constraint fk_model_no foreign key(model_no) references cars(model_no), constraint fk_part_no foreign key(part_no) references parts(part_no) ); 1)create table cars ( model_no char(10) primary key, brand char(20) not null, make varchar(40), style char(20), year date, description varchar(200)); 2)create table parts ( part_no char(12) primary key, name char(20) unique, description varchar(200));
3.2.2.2 修改基本表(P89) SQL语言使用ALTER TABLE命令来修改基本表 格式: 注意: [ADD <新列名><数据类型>[ <完整性约束定义]] [ ADD <表级完整性约束> ] [ MODIFY <列名><数据类型> ] [ DROP <完整性约束定义> ]; 注意: 1. 使用ADD方式增加的新列自动填充NULL值,所以增加的新列不能指定NOT NULL约束 。
例:向student表中增加“入学时间”列,其数据类型为日期型,不允许为空。 表中无数据时: Alter Table student ADD scome date not null; 表中有数据时: Alter Table student ADD scome date; Update student set scome ctod(‘1999-01-01’); Alter Table student Modify scome not null;
例: 将students表的cert_code改为id_no。 例:向sc表中增加主键约束,名字为pk_sno_cno。 Alter Table sc Add constraint pk_sno_cno primary key(sno,cno); 例:删除sc表中外键约束fk_cno。 Alter Table sc drop constraint fk_cno; 例: 删除学生姓名必须取唯一值的约束 ALTER TABLE Student Drop UNIQUE(Sname) 例: 将students表的cert_code改为id_no。 Alter table students rename cert_code to id_no; 例: 将students表名改为student。 Alter table students rename student;
2.使用MODIFY方式时: ①不能将含有空值的列的定义修改为NOT NULL约束; ② 若列中已有数据,则不能减少该列的宽度,也不能改变其数据类型; ③ 只能修改NULL|NOT NULL约束,其它类型的约束在修改之前必须先删除,然后再重新添加修改过的约束定义。 例: 将年龄的属性类型改为半字长整数 Alter table student Modify sage smallint; 将姓名的属性类型改为最大为40的可变长度字符 Alter table student Modify sname varchar(40);
有些DBMS可以修改属性约束 Alter Table MovieStar Modify gender Null; Alter Table MovieStar Modify gender Check(gender In (‘F’, ‘M’); Add Constraint RightTitle Check( gender = ‘F’ OR name Not Like ‘Ms.%’); Drop Constraint RightTitle;
SQL没有提供删除属性列的语句,可以间接实现。先将表中要保留的列及其内容复制到一个新表中,然后删除原表,在将新表命名为原表名。 例: 删除students中的列cert_code。 1)Create table students_1 as (select sno,sname,ssex,sage,sdept from students); 2)Drop table students; 3)Alter table students_1 rename students;
3.2.2.3 删除基本表(P90) 删除表的语法格式: DROP TABLE <表名> 注意: 用户只能删除自己建立的表,不能删除其他用户所建的表。 基本表定义一旦被删除,表中数据,此表上建立的索引和视图都将自动被删除掉。 有的系统(如Oracle),删除基本表后建立在此表上的视图定义仍然保留在数据字典中。但用户使用时就报错。 例:删除学生基本表Student DROP TABLE Student;
§ 3.2.3 设计、创建和维护索引 3.2.3.1 索引的含义 3.2.3.2 索引的分类 3.2.3.3 建立索引 § 3.2.3 设计、创建和维护索引 3.2.3.1 索引的含义 3.2.3.2 索引的分类 3.2.3.3 建立索引 3.2.3.4 删除索引
3.2.3.1 索引的含义 索引是一种数据结构,是对照表、指针表。 索引是为了加速对表中元组的检索而创建的一种分散存储结构。 索引是对表而建立的,由除存放表的数据页面以 外的索引页面组成。 索引加快查询速度,减慢更新的速度。
3.2.3.2 索引的分类 1. 按照索引记录存放位置:聚集索引与非聚集索引 2. 唯一索引的概念 3. 复合索引的概念 聚集索引:按照索引的字段排列记录,并且依照排好的顺序将记录存储在表中,即索引项的顺序与表中记录的物理顺序一致。 非聚集索引:按照索引的字段排列记录,但是排列的结果并不会存储在表中,而是另外存储。 2. 唯一索引的概念 唯一索引:表示表中每一个索引值只对应唯一的数据记录。不同元组中索引字段的值不允许相同。 3. 复合索引的概念 复合索引:是将两个字段或多个字段组合起来建立的索引,而单独的字段允许有重复的值。
3.2.3.3 建立索引 语法: CREATE [UNIQUE] [CLUSTER] INDEX <索引名> ON <表名> (<列名> [次序] [{,<列名>}] [次序]…); 次序用来指定索引值的排列顺序,可为ASC(升序)或DESC(降序),缺省值为ASC。 例1:为students表按sname建唯一索引 Create unique index idx_sname on students(sname); 例2:为courses表按cname建聚集索引 Create cluster index idx_cname on courses(cname); 例3:为sc表按sno降序和cno升序建唯一索引 Create unique index idx_sno_cno on sc(sno desc,cno);
注意: 例4: 1. 改变表中的数据(如增加或删除记录)时,索引将自动更新。索引建立后,在查询使用该列时,系统将自动使用索引进行查询。 CREATE UNIQUE INDEX StuSno ON Student(SNO); CREATE UNIQUE INDEX CoucNo ON Course(CNO); CREATE UNIQUE INDEX Scno ON SC(SNO ASC,CNo ASC); 注意: 1. 改变表中的数据(如增加或删除记录)时,索引将自动更新。索引建立后,在查询使用该列时,系统将自动使用索引进行查询。 2. 索引数目无限制,但索引越多,更新数据的速度越慢。对于仅用于查询的表可多建索引,对于数据更新频繁的表则应少建索引。
3.2.3.4 删除索引 索引一经建立,就由系统使用和维护它。 句法: DROP INDEX <索引名>; 不需用户干预建立索引是为了减少查询操作的时间。 但如果数据项删改频繁,系统会花费许多时间来维护索引。这时,可以删除一些不必要的索引。 句法: DROP INDEX <索引名>; 例1:删除Student表的stuname索引 DROP INDEX stuname; 例2:Drop index idx_sname;
§3.3 SQL数据查询(P91-P116) 3.3.1 SELECT命令的格式与基本使用 3.3.2 单表查询 3.3.3 连接查询 3.3.2 单表查询 3.3.3 连接查询 3.3.4 嵌套查询 3.3.5 集合查询
3.3.1 SELECT命令的格式与基本使用 SELECT语句的一般格式为: 查询的结果是仍是一个表。 对结果排序 SELECT [ALL│DISTINCT] <目标列表达式> [,<目标列表达式]….. FROM <表名或视图名> [,<表明或视图名>]….. [WHERE <条件表达式> ] [GROUP BY <列名1> [HAVING<条件表达式>]] [ORDER BY <列名2> [ASC│DESC]; 查询的结果是仍是一个表。 与聚集函数连用 对结果排序
SELECT语句的执行过程是 : 根据WHERE子句的条件表达式,从FROM子句指定的基本表或视图中找出满足条件的元组; 如果有GROUP子句,则将结果按<列名1>的值进行分组,该属性列值相等的元组为一组; 如果GROUP子句带HAVING短语,则只有满足指定条件的组才予输出; 如果有ORDER子句,则结果表还要按<列名2>的值的升序或降序排序。
3.3.2 单表查询(P92-P94) 3.3.2.1 查询语句中的投影操作 3.3.2.2 条件查询 3.3.2.3 对查询结果排序 3.3.2.1 查询语句中的投影操作 3.3.2.2 条件查询 3.3.2.3 对查询结果排序 3.3.2.4 常用集函数及统计汇总查询 3.3.2.5 分组查询
3.3.2.1 查询语句中的投影操作 投影操作(选取表中的若干列)是从关系的属性集中选择属性子集(与关系代数的投影运算等同) ,即由关系的部分列组成一个新关系。 1.查询表中指定的部分列 查询结果中的重复行可通过“DISTINCT”被去掉 2.查询表中全部列 用‘ * ’表示表的全部列名,而不必逐一列出 3.查询经过计算的值 4.选择表中若干元组,消除取值重复的解
SELECT语句中的“目标列表达式”的语法图 引用返回 目标列表达式 列名 目标列表达式 ⌴ 别名 , 表达式 别名 ‘ 字符串 ’ 算术表达式 表达式 SELECT语句中的“目标列表达式”的语法图
利用投影查询时<目标列表达式>不仅可以表中属性列,还可以是算术表达式。 Select sname,2003-sage from student; 利用投影查询时<目标列表达式>不仅可以是算术表达式,还可以是字符串常量、函数等。 Select sno,date(),birth_date from students; 利用投影查询可控制列名的顺序,并可通过指定别名改变查询结果的列标题的名字。
1.查询表中指定的部分列 例: 查询全体学生的学号与姓名(P93例1 ): SELECT SNO,SName FROM Student 例: 查询全体学生的学号与姓名(P93例1 ): SELECT SNO,SName FROM Student 查询全体学生的学号,姓名与所在的系( P93例2 ): SELECT SName,SNo,SDept
2.查询表中全部列 将表中的所有属性列都选出来,可以有两种方法。 一种方法就是在SELECT关键字后面列出所有列名。 另一种是,如果列的显示顺序与其在基本表中的顺序相同,也可以简单地将<目标表达式>指定为*。 例:查询全体学生的详细记录:可列出全部列名,可用*号代替( P93例3 ) : SELECT * FROM Student 等价于 SELECT Sno,Sname,Ssex,Sage,Sdept
3.查询经过计算的值 <目标列表达式>不仅可以是表中的属性列,也可以是表达式。 例:查询经过计算的值 查全体同学的姓名及其出生年份(见P93例4) SELECT SName,1996-SAge FROM Student; 查询结果见P93下部表。 Sname 1996-Sage 李勇 1976 刘晨 1977 王敏 1978 张立 再例:查询全体同学的姓名,出生年份和所在系,要求用小写字母表示系名。 SELECT SName NAME ,’Year Of Birth:’,2003-SAge,ISLOWER(SDept) FROM Student; 查询结果见P94上部表。 Sname ‘Year of Birth:’ 1996-Sage ISLOWER(SDept) 李勇 Year of Birth: 1976 cs 刘晨 1977 is 王敏 1978 ma 张立
3.查询经过计算的值 Cont.01 用户可以通过指定<别名>改变查询结果的<列标题>,这对于含算术表达式、常量、函数名的目标列表达式,尤为有用! SELECT SName NAME,’Year Of Birth:’ BIRTH,2001-SAge BIRTHDAY,ISLOWER(SDept)DEPARTMENT FROM Student; 查询结果见P94中部表。 NAME BIRTH BIRTHDAY DEPARTMENT 李勇 Year of Birth: 1976 cs 刘晨 1977 is 王敏 1978 ma 张立
4.选择表中若干元组,消除取值重复的解 SELECT查询结果不像关系代数,自动去掉重复元组,必须用DISTINCT进行去掉,即消除取值重复的解。 例:查询选修了课程的学生学号(P95例6) SELECT SNO FROM SC; 从选课表中,对列SNO进行投影得到选课的学生号,但本句的结果数与库中记录条数相同,有许多重复项,因一个学生选了多门课。 Sno 95001 95002 SELECT DISTINCT SNO FROM SC; 缺省时,为ALL。加上DISTINCT后,就消除了结果中的重复元组。 95002 95001 Sno
3.3.2.2 条件查询 条件查询,是指从关系中选择满足条件的部分元组,通过WHERE子句来实现。 WHERE子句通过三部分来描述: 3.3.2.2 条件查询 条件查询,是指从关系中选择满足条件的部分元组,通过WHERE子句来实现。 WHERE子句通过三部分来描述: 1.列名;2.运算符;3.列名、常数。 WHERE子句常用的查询条件: 查询条件 谓 词 比较 =,>,<, >=,<=,!=,<>,!>,!<; NOT +上述比较运算符 确定范围 BETWEEN…AND,NOT BETWEEN…AND 确定集合 IN,NOT IN 字符匹配 LIKE ,NOT LIKE 空值 IS NULL ,IS NOT NULL 多重条件 AND ,OR
3. 确定集合 3.3.2.2 条件查询 Cont.01 1. 比较大小 2. 确定范围 4. 字符匹配 5. 涉及空值的查询 1. 比较大小 2. 确定范围 3. 确定集合 4. 字符匹配 5. 涉及空值的查询 6. 多重条件查询
1. 比较大小(P96) 例(1):查询计算机系学生的名单 例(2):查询所有年龄在20岁以下的学生姓名及其年龄 这里,DISTINCT短语的语义为:当一个学生有多门课不及格,他的学号也只列一次。 1. 比较大小(P96) 例(1):查询计算机系学生的名单 SELECT SName FROM Student WHERE SDept=’CS’; 例(2):查询所有年龄在20岁以下的学生姓名及其年龄 SELECT SName,SAge FROM Student WHERE SAge<20;(或:SAge NOT>=20) 例(3):查询考试成绩有不及格的学生学号。 SELECT DINSTINCT SNo FROM SC WHERE Grade<60;
2. 确定范围(P96) 谓词BETWEEN…AND…和NOT BETWEEN…AND…可以用来查询属性值在(或不在)指定范围内的元组,一般这个范围是个数值型。 例(1):查询年龄在20-30岁(包括20岁和30岁)之间的学生姓名、系别和年龄。 SELECT SName,SDept,SAge FROM Student WHERE SAge BETWEEN 20 AND 30; 等价于(Sage >=20 and Sage <=30) 例(2) :查询年龄不在20-30岁之间的学生姓名、系别和年龄。 SELECT SName,SDept,SAge FROM Student WHERE SAge NOT BETWEEN 20 AND 30;
3. 确定集合(P97) 利用“IN”操作可以查询属性值属于指定集合的元组。 利用“NOT IN”可以查询指定集合外的元组。 例(1):查询信息系(IS),数学系(MA)和计算机系(CS)学生的姓名和性别。 SELECT SName,SSex FROM Student WHERE SDept IN (‘CS’,’MA’,’IS’); 例(2):查询既不是信息系、数学系,也不是计算机系学生的姓名和性别。 SELECT SName,SSex FROM Student WHERE SDept NOT IN (‘CS’,’MA’,’IS’);
4. 字符匹配(P97) 谓词LIKE可以用来进行字符串的匹配,其一般格式如下: 其中: [Not]LIKE ‘<匹配串>’ [ESCAPE ‘<换码字符>’] 匹配串是一个完整的字符串,也可以含有通配符“%”和“_”。 其中: %(百分号):代表任意长度(长度可以为零)的字符串。 例如a%b表示以a开头,以b结尾的任意长字符串。 如:acb,addgb,ab等都满足该匹配串。 _(下划线):代表任意单个字符。 例:a_b代表以a开头,以b结尾的长度为3的任意字符串,acb,a1b,afb,abb
4. 字符匹配(P97) Cont.01 例(1):查询学号为95001的学生详细情况。 SELECT * FROM Student WHERE SNo LIKE ‘95001’; 等价于SNo=’95001’ 如果LIKE后面的匹配串中不含通配符,则可以: 用“=”运算取代LIKE谓词; 用!=或<>(不等于)取代NOT LIKE谓词。 例(2):查询所有姓刘的学生的姓名、学号和性别。 SELECT SName,SNo,SSex FROM Student WHERE SName LIKE ‘刘%’; 例(3):查询姓“欧阳”且全名为3个字的学生姓名。 SELECT SName WHERE SName LIKE ‘欧阳__’;
4. 字符匹配(P97) Cont.02 例(4):查询所有不姓刘的学生的姓名 SELECT SName,SNo FROM Student WHERE SName NOT LIKE ‘刘%’; 如果用户查询的字符串本身就含有’%’或’_’,这时要用ESCAPE’<换码字符>’补语对通配符进行转义,使’%’和’_’不具备通配符意义。
4. 字符匹配(P97) Cont.03 例(5):查询DB_DESIGN课程的课程号和学分 SELECT CNO,Ccredit FROM Course WHERE Cname Like ‘DB\_Design’ ESCAPE ‘\’; 例(6):查询”DB_”以开头,且倒数第三个字符为i的课程的详细情况 SELECT CNO,CCredit WHERE CName Like ‘DB\_%i__’ ESCAPE ‘\’;
5. 涉及空值的查询(P98) 空值比较时: 只能用IS NULL,IS NOT NULL。 不能用’=’或’<>’ ‘!=’比较。 某个字段没有值,称之为具有空值(NULL): 空值不同于零和空格; 它不占任何存储空间。 例(1):某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。(P98-99) SELECT Sno,Cno FROM SC WHERE Grade IS NULL; 注意这里的“IS”不能用等号(=)来代替。
6. 多重条件查询 当WHERE子句需要指定一个以上的查询条件时,则需要使用逻辑运算符AND、OR和NOT将其连结成复合的逻辑表达式。 6. 多重条件查询 当WHERE子句需要指定一个以上的查询条件时,则需要使用逻辑运算符AND、OR和NOT将其连结成复合的逻辑表达式。 其优先级由高到低为:NOT、AND、OR,用户可以使用括号改变优先级。 例(1):查询计算机系年龄在20岁以下的学生姓名 SELECT SName FROM Student WHERE SDept=’CS’ AND SAge<20; 例(2):查询计算机系和数学系学生姓名 WHERE SDept=’CS’ OR SDept=’MA’; 与IN集合查询等价
3.3.2.3 对查询结果排序 使用ORDER BY子句对查询结果按照一个或多个属性列的升序(ASC)或降序(DESC)排序,缺省值为升序。 3.3.2.3 对查询结果排序 使用ORDER BY子句对查询结果按照一个或多个属性列的升序(ASC)或降序(DESC)排序,缺省值为升序。 对于空值: 若按升序排,含空值的元组将最后显示。 若若按降序排,含空值的元组将最先显示。 例(1):查询选修了3号课程的学生的学号及其成绩,查询结果按分数的降序排序。 (P100) SELECT SNo,Grade FROM SC WHERE CNo=‘3’ ORDER BY Grade DESC; 例(2):查询全体学生情况,查询结果按所在系的系号升序排列,同系的学生按年龄降序排列。(P99-100) SELECT * FROM Student ORDER BY SDept,SAge DESC;
3.3.2.4 常用集函数及统计汇总查询 SQL提供了许多集函数,增强了基本检索能力。 SQL提供的集函数,主要有: (P100) 3.3.2.4 常用集函数及统计汇总查询 SQL提供了许多集函数,增强了基本检索能力。 SQL提供的集函数,主要有: (P100) COUNT([DISTINCT|ALL]* ) 统计元组个数 COUNT([DISTINCT|ALL]<列名>) 统计一列中值的个数 SUM([DISTINCT|ALL]<列名>) 计算一列值的总和(数值型字段) AVG([DISTINCT|ALL]<列名>) 计算一列值的平均值(数值型字段) MAX([DISTINCT|ALL]<列名>) 计算一列值中的最大值 MIN([DISTINCT|ALL]<列名>) 计算一列值中的最小值
3.3.2.4 常用集函数及统计汇总查询 Cont.01 注意: 对查询结果分组: u 如果指定DISTINCT补语,则表示在计算时要取消指定列中的重复值; u 如果不指定DISTINCT补语或指定ALL补语(缺省为ALL)则表示不取消重复值。 对查询结果分组: 用GROUP BY子句 将查询结果按某一列或多列值分组 值相等的为一组。
3.3.2.4 常用集函数及统计汇总查询 Cont.02 例(1):查询学生总人数(P100) SELECT COUNT(*) FROM Student; 例(2):查询选修了课程的学生人数(P100) SELECT COUNT(DISTINCT SNO) FROM SC; 例(3):查询每个同学的平均成绩 SELECT SNO,AVG(Grade) FROM SC GROUP BY SNO;
3.3.2.4 常用集函数及统计汇总查询 Cont.03 例(4):查询选修1号课程的学生最高分数(P100) SELECT MAX(Grade) FROM SC WHERE CNO=’1’; 例(5):查询每门课的最高成绩 SELECT CNO,MAX(Grade) GROUP BY CNO; 属性名应出现在分组的属性中。
3.3.2.4 常用集函数及统计汇总查询 Cont.04 例(6):查询选修了3门课以上的学生学号(P101) SELECT SNO FROM SC GROUP BY SNO HAVING COUNT(*)>2; WHERE与HAVING子句的区别在于作用对象不同: WHERE作用于表或视图,从中选择满足条件的元组; HAVING补语作用于组,从中选择满足条件的元组。 例(7):查询每个系男女生的平均年龄。 SELECT SDept,SSex,AVG(SAge) FROM Student GROUP BY SDept,Ssex;
3.3.2.5 分组查询 GROUP BY子句,可以将查询结果表按某一列或多列值分组,值相等的为一组。 3.3.2.5 分组查询 GROUP BY子句,可以将查询结果表按某一列或多列值分组,值相等的为一组。 若在分组后,还要按照一定的条件进行筛选,则需使用HAVING子句。 如果没有对查询结果分组,则集函数作用于整个查询结果;否则,集函数作用于每个分组。 例:查询每个系男女生的平均年龄。 SELECT sdept,ssex,AVG(sage) FROM student GROUP BY sdept,ssex;
3.3.2.5 分组查询 Cont.01 当在一个SQL查询中,同时使用WHERE子句,GROUP BY 子句和HAVING子句时,其顺序是WHERE-GROUP BY- HAVING。 WHERE与HAVING子句的根本区别在于作用对象不同。 WHERE子句作用于基本表或视图,从中选择满足条件的元组; HAVING子句作用于组,选择满足条件的组,必须用于GROUP BY子句之后,但GROUP BY子句可没有HAVING子句。
3.3.3 连接查询(P101-P105) 引用返回 同时涉及两个以上的表的查询,称为连接查询。 连接操作是从笛卡尔积中选择满足条件的元组 连接类型: 内连接: 使用比较运算符,进行表间某列或某些列数据的比较操作,并列出这些表中与连接条件相匹配的数据行。 内连接分为等值连接、非等值连接和自身连接。 外连接: 外连接不仅要列出与连接条件相匹配的数据行,而是列出左表、右表或两个表中所有符合查询条件的数据行。 外连接分为左外连接、右外连接和全外连接。 交叉连接(广义笛卡尔积): 交叉连接不带WHERE 子句,它返回被连接的两个表所有数据行的笛卡尔积,返回到结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
3.3.3 连接查询(P101-P105) Cont.01 对两个或两个以上表的查询,都要进行连接查询,连接操作。 连接包括: 内连接 等值连接 自身连接 非等值连接 自然连接 外连接 符合条件连接 两个表中必须有可比属性列。 内连接 交叉连接 外连接
3.3.3 连接查询(P101-P105) Cont.02 3.3.3.1 等值连接与非等值连接 3.3.3.2 自身连接 3.3.3.1 等值连接与非等值连接 3.3.3.2 自身连接 3.3.3.3 外连接 3.3.3.4 交叉连接(广义笛卡尔积) 3.3.3.5 复合条件连接
3.3.3.1 等值连接与非等值连接 连接查询中,用来连接两个表的条件,称为连接条件或连接谓词。 其一般格式为: 3.3.3.1 等值连接与非等值连接 连接查询中,用来连接两个表的条件,称为连接条件或连接谓词。 其一般格式为: [<表名1>.] <列名1> <比较运算符> [<表名2>.] <列名2> 比较运算符主要有:=、>、<、>=、<=、!= 当比较运算符为“=”时,称为等值连接,其他情况为非等值连接。(P102页例32)
3.3.3.1 等值连接与非等值连接 Cont.01 DBMS执行连接操作的过程: 先在表1中找到第一个元组, 然后从头开始扫描表2,逐一查找满足连接条件的元组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组。 表2全部查找完后,再找表1中第二个元组,然后从头开始扫描表2…。 重复上述操作,直到第1个表中全部元组处理完。 表1 表2 结果表
<表名>.<属性名> 3.3.3.1 等值连接与非等值连接 Cont.02 例:查询计算机系学生选课情况,要求有学号、姓名、所在系、课程号、课程名、成绩。 (P102页例32) SELECT Student.SNo,SName,SDept,Course.CNo,CName,Grade FROM Student,SC, Course WHERE Student.SNo=SC.SNo AND Course.CNo=SC.CNo AND LOWER(SDept)=’CS’; 含义: A)这是自然连接,去掉了同名的属性列。(等值连接的一种特例) B)如果没有WHERE子句,即无连接条件,将实现广义笛卡尔积,有些元组无意义,查询结果数应为n1*n2*n3。 C)如果属性列在n个表中出现,其前面要以表名限制。格式为: <表名>.<属性名>
3.3.3.1 等值连接与非等值连接 Cont.03 当有两个以上的表进行连接时,称为多表连接。 例:查询每个学生的学号、姓名、选修的课程名及成绩。 Select student.sno,sname,cname,grade from student,sc,course where student.sno=sc.sno and sc.cno=course.cno; 去掉等值连接中目标列中重复的属性列则称为自然连接。 P102例33
3.3.3.2 自身连接(P103) 定义:连接操作可以是一个表与其自身进行连接,称为表的自身连接。 表的别名定义: 引用返回 3.3.3.2 自身连接(P103) 定义:连接操作可以是一个表与其自身进行连接,称为表的自身连接。 表的别名定义: 在FROM子句中,进行表的别名定义 格式:FROM <表名><别名1>,<表名><别名2> 实例:见P103-104例34。
3.3.3.3 外连接(P104) 1)由来与必要性 2)外连接的表示方法 3)外连接的语义 4)外连接的类型 在通常情况下,只有满足连接条件的元组才能作为输出结果。 若一个表的连接属性在另一个表中为“空值”,即一个表与另一个表的空值进行连接。由于对应的表中没有相应的元组,因而需要增加一个“万能”行(元组值全为空值),也就是说----需要使用“外连接”(Outer Joint)。 2)外连接的表示方法 在连接谓词的某一边加符号“*”(有的DBMS用“+”)。 3)外连接的语义 (1)就象是为符号“*”所在边的表(本例为SC)增加一个“万能”行; (2) “万能”行的元组值全为空值。 4)外连接的类型 (1)外连接符“*”出现在连接条件的右边,称为“右外连接”; (2)外连接符“*”出现在连接条件的左边,称为“左外连接”。
3.3.3.3 外连接 Cont.01 具体分为以下几种: LEFT (OUTER) JOIN:显示符合条件的数据行以及左边表中不符合条件的数据行,此时右边数据行会以NULL来显示,此称为左连接; 例:select student.sno,sname,ssex,sage,sdept,cno,grade from (student left outer join sc on student.sno=sc.sno); RIGHT (OUTER) JOIN:显示符合条件的数据行以及右边表中不符合条件的数据行,此时左边数据行会以NULL来显示,此称为右连接; 例:select student.sno,sname,ssex,sage,sdept,cno,grade from (student right outer join sc on student.sno=sc.sno); FULL (OUTER) JOIN:显示符合条件的数据行以及左边表和右边表中不符合条件的数据行,此时缺乏数据的数据行会以NULL来显示; 例: Select * From ( Student Full Outer Join SC on Student.sno = SC.sno) 当将JOIN 关键词放于FROM子句中时,应有关键词ON与之相对应,以表明连接的条件。
3.3.3.3 外连接 Cont.02 例如:S SC 要连接的输出结果为:所有学生及其选课情况。 SNO SName 001 张三 002 李四 003 王五 SNO CNO Grade 001 1 85 2 78 3 90 要连接的输出结果为:所有学生及其选课情况。 SNO SName CNo Grade 001 张三 1 85 2 78 3 90 002 李四 空 003 王五
3.3.3.3 外连接 Cont.03 SELECT S.SNo,SName,CNo,Grade FROM S,SC WHERE S.SNo=SC.SNo(*); (右外连接) 或SELECT S.SNo,SName,CNo,Grade FROM S Left Outer Join SC On S.SNo=SC.SNo; (左外连接)
3.3.3.4 交叉连接(广义笛卡尔积) CROSS JOIN:将一个表的每一笔数据和另一表的每笔数据匹配成新的数据行。 例: 3.3.3.4 交叉连接(广义笛卡尔积) CROSS JOIN:将一个表的每一笔数据和另一表的每笔数据匹配成新的数据行。 例: SELECT sno,sname,cno,cname FROM student,course;
3.3.3.5 复合条件连接( P105 ) 若连接查询的WHERE 子句中有多个连接条件,称为复合条件连接。 连接条件中包含: 连接谓词(比较连接属性) 限定条件(对连接的表进行选择) 例:查询选修2号课程且成绩在90分以上的所有学生。 (P105页例35)。 SELECT Student.Sno,Sname FROM Student,SC WHERE Student.Sno=SC.Sno AND /*连接谓词*/ SC.Cno=‘2’ AND /*其他限制条件*/ SC.Grade>90 /*其他限制条件*/ 复合条件连接
3.3.4 嵌套查询(P106-P113) 定义: 用途: 查询块:一个SELECT-FROM-WHERE语句称为一个查询块。 嵌套查询:将一个查询块嵌套在另一个查询块的WHERE子句或HAVING补语的条件中的查询称为嵌套查询。 用途: 嵌套查询使我们可以用多个简单查询构成复杂查询,从而增强SQL的查询功能。
3.3.4 嵌套查询(P106-P113) Cont.01 嵌套查询的层次划分 l 上层的查询块称为“外层查询”或“父查询”; 注意事项 l SQL语言允许多层嵌套查询,以层层嵌套的方式来构造程序,正是SQL中“结构化”的含义所在。 l 但是,子查询的SELECT语句中,不能使用ORDER BY子句,ORDER BY子句只能对最终查询结果排序。 嵌套查询的一般求解方法 l 总体策略----由里向外处理。即: l 每个子查询在上一级查询处理之前求解; l 子查询的结果用于建立其父查询的查找条件。
3.3.4 嵌套查询(P106-P113) Cont.02 引用返回 不相关子查询:子查询的查询条件不依赖于父查询。 相关子查询:子查询的查询条件依赖于父查询的某个属性值 嵌套查询中的谓词: 带[not]IN ; 比较运算符; ANY,ALL; [not]EXISTS 适用于子查询的结果是一个集合(P106-109) 由内查询开始向外 子查询返回单值可用比较运算符(P109-111) 与比较符连用;用集函数更好些(P111-114) 由外到内 ⑴ EXISTS代表存在量词“”。 ⑵ 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真假值。 ⑶ EXISTS与NOT EXISTS可等价替代其它形式查询,但反之不成立。 ⑷ EXISTS查询是高效方法。 ⑸一般处理过程(P112)。
3.3.4 嵌套查询(P106-P113) Cont.03 有的嵌套查询可以用连接查询来实现,但并非所有嵌套查询都可以用连接查询替换。 带IN、比较运算符、ANY、ALL谓词的查询都可以用EXIST查询等价替换。 全称量词(For ALL)和逻辑蕴涵 (Implication)可以用EXISTS来替换。(等价替换) (x)P ( x(P)) pq pq 书中P113页,例43,44 牢牢地熟悉书上的例子。 问题:查询不选修1号课程的全部学生姓名。 见P112例42。
3.3.4 嵌套查询(P106-P113) Cont.04 3.3.4.1 返回一个值的子查询 3.3.4.2 返回一组值的子查询 3.3.4.1 返回一个值的子查询 3.3.4.2 返回一组值的子查询 3.3.4.3 带有EXISTS谓词的子查询(P111) 练习 答案
3.3.4.1 返回一个值的子查询(P109 带比较符子查询) 含义:“返回一个值的子查询”=“带比较运算符的子查询”,是指—父查询与子查询之间用比较运算符进行连接。 时机:当用户能确知“内层子查询”的返回值只有一个(是单值)时,可以使用比较运算符(=, >, <, >=, <=, !=)将父查询和子查询连接起来。 例1:找出与95001同龄的学生(一个学生只有一个年龄)。 Select * From Student Where sage = ( Select sage Where sno = ‘95001’ ) (外层)父查询 返回结果满足条件 (内层)子查询 返回结果是单值 比较运算符
3.3.4.1 返回一个值的子查询 Cont.01 注意:子查询一定要跟在比较运算符之后。 例2:下列写法是错误的。 Select * From Student Where ( Select sage Where sno = ‘95001’ ) = sage 产生错误原因是:将子查询放在了比较运算符“=”的前边。
3.3.4.2 返回一组值的子查询(P107 带IN谓词子查询) 如果子查询的返回值不止一个,而是一个集合时: (1)可以采用谓词IN; (2)或者,在比较运算符和子查询之间插入ANY或ALL。 带有IN谓词的子查询(P107 例37、38) 标量值与子查询返回集中的某一个相等,true IN 被用来测试多值中的成员 例1:查询选修‘C01’课程的学生的学号、姓名。 Select sno,sname From Student Where sno IN ( Select sno From SC Where cno = ‘C01’); 子查询 多行一列
3.3.4.2 返回一组值的子查询 Cont.01 例2:查询选修了‘数据库’的学生的学号和姓名。 Select sno,sname From Student Where sno IN ( Select sno From SC Where cno IN ( Select cno From Course Where cname = ‘数据库’ )) 不相关子查询:子查询的查询条件不依赖于父查询。 (见以下例3、例4:各子查询只执行一次,其结果用于父查询。或见P107-109例37、例38。) 执行3 由内向外 执行2 执行1
3.3.4.2 返回一组值的子查询 Cont.02 引用返回 例3:查询与“刘晨”在同一个系学习的学生。(P107 例37) 先分步来完成此查询,然后再构造嵌套查询。 (1)确定“刘晨”所在的系名 SELECT Sdept FROM Student WHERE Sname=‘刘晨’; 执行结果: IS Sdept (2)查询所有在IS系学习的学生 SELECT Sno,Sname,Sdept FROM Student WHERE Sdept =‘IS’; 被嵌入到 执行结果: IS 张立 95004 刘晨 95001 Sdept Sname Sno
3.3.4.2 返回一组值的子查询 Cont.03 将第(1)步查询嵌入到第(2)步查询的条件中,SQL语句如下: SELECT Sno,Sname,Sdept FROM Student WHERE Sdept IN (SELECT Sdept WHERE Sname=‘刘晨’); DBMS求解该查询时,实际上也是分步去做的,类似于上面写的分步过程。
3.3.4.2 返回一组值的子查询 Cont.04 例3中的查询,也可以用自身连接来完成: SELECT S1.Sno,S1.Sname,S1.Sdept FROM Student S1, Student S2 WHERE S1.Sdept = S2.Sdept AND S2.Sname=‘刘晨’ ; 可见,实现同一查询可以有多种方法,当然不同方法其执行效率可能会有差别,甚至会差别很大。 例3中的父查询和子查询均引用了Student表,可以像自身连接那样用别名将父查询中的Student表与子查询中的Student表区分开: SELECT Sno,Sname,Sdept FROM Student S1 WHERE S1.Sdept IN (SELECT Sdept FROM Student S2 WHERE S2.Sname=‘刘晨’ );
3.3.4.2 返回一组值的子查询 Cont.05 例4:查询选修了课程名为“信息系统”的学生的学号和姓名。 本查询涉及学号、姓名和课程名三个属性。 学号、姓名存放在Student表中; 课程名存放在Course表中; 但Student与Course两个表之间没有直接联系,必须通过SC表建立它们二者之间的联系。 所以本查询实际上涉及了三个关系。 嵌套查询语句: SELECT Sno,Sname (3)最后在Student关系中取出 FROM Student 相应的Sno和Sname WHERE Sno IN (SELECT Sno (2)然后在SC关系中找出选修 FROM SC 了3号课程的学生的学号 WHERE Cno IN (SELECT Cno (1)首先在Course关系中找出 FROM Course “信息系统”的课程号,结 WHERE Cname=‘信息系统’)); 果为3号 查询结果: 刘晨 95002 李勇 95001 Sname Sno
3.3.4.2 返回一组值的子查询 Cont.06 例4的查询同样可以用连接查询来实现: SELECT Sno,Sname FROM Student,SC,Course WHERE Student.Sno=SC.Sno AND SC.Cno=Course.Cno AND Course.Cname=‘信息系统’; 从例3、例4可以看出,查询涉及多个关系时,用嵌套查询逐步求解,层次分明,易于构造,具有结构化程序设计的优点(这是我们所追求的!)。 有些嵌套查询可以用连接运算替代,有些是不能替代的。到底采用哪种方法,用户可以根据自己的习惯确定。 不相关子查询是最简单的一类子查询。其各子查询都只执行一次,其结果用于父查询。子查询的查询条件不依赖于父查询。
3.3.4.2 返回一组值的子查询 Cont.07 例5:找出年龄最小的学生 父查询与多值子查询之间的比较需用All来连接(P109-111) 标量值s比子查询返回集R中的每个都大时, s>All R 为True All表示“所有” > all、< all、<=all、>=all、<> all <> all 等价于 not in 例5:找出年龄最小的学生 Select * From Student Where sage < all (Select sage From Student )
3.3.4.2 返回一组值的子查询 Cont.08 s > Any R为True 父查询与多值子查询之间的比较需用Any来连接(P109-111) 标量值s比子查询返回集R中的某一个都大时 s > Any R为True Any表示某一个,只要有一个即返回真 > any、< any、<=any、>=any、<> any = any 等价于 in、<> any 不等价于 not in 例6:找出不是最小年龄的学生 Select * From student Where sage > any ( Select sage From Student );
3.3.4.2 返回一组值的子查询 Cont.09 例7:找出具有最高平均成绩的学号及平均成绩 Select sno ,avg(grade) From SC Group By sno Having avg(grade) >= all (Select avg(grade) Group By sno);
3.3.4.3 带有EXISTS谓词的子查询(P111) 带有EXISTS的子查询,不返回任何实际数据,它只得到逻辑值“真”或“假”。 相关子查询:子查询的查询条件依赖于外层父查询的某个属性值,即外层元组的属性作为内层子查询的条件。 相关子查询的执行顺序是: 首先选取父查询表中的第一行记录,内部的子查询利用此行中相关的属性值进行查询, 然后父查询根据子查询返回的结果判断此行是否满足查询条件。 如果满足条件,则把该行放入父查询的查询结果集合中。 重复执行这一过程,直到处理完父查询表中的每一行数据。 相关子查询与不相关子查询的区别
3.3.4.3 带有EXISTS谓词的子查询 Cont.01 例1:列出选修了C01课程的学生的学号、姓名 Select sno,sname From Student Where Exists ( Select * From SC Where SC.sno = Student.sno And cno = ‘C01’); 例2:列出得过100分的学生的学号、姓名 Where Exists ( Select * Where SC.sno = Student.sno And grade = 100); 他选修了这门课程 他选修了这门课程
3.3.4.3 带有EXISTS谓词的子查询 Cont.02 例3:列出没有选C01课程的学生的学号、姓名 Select sno,sname From Student Where Not Exists ( Select * From SC Where SC.sno = Student.sno And cno = ‘C01’); 这门课程他没选
3.3.4.3 带有EXISTS谓词的子查询 Cont.03 例4:查询选修了‘C01’课程的学生的系主任 Select manager From department Where Exists ( Select * From student Where sdept = department.depid And Exists ( Select * From SC Where SC.sno = student.sno And cno = ‘C01’)) 这个系有学生存在 他选了这门课程
3.3.4.3 带有EXISTS谓词的子查询 Cont.04 例5:查询选修了所有课程的学生的姓名(ForAll) Select sname From Student Where Not Exists ( Select * From Course From SC Where Student.sno = SC.sno And SC.cno = Course.cno)) 这样的课是不存在的 这门课他没选
综合实例 例6:有供应商S,零件关系P,工程项目J,供应关系SPJ(供应商供应某零件PNO给某项目JNO的数量为QTY)。 S: P: 供应商编号 供应商名称 供应商所在城市 Sno Sname CITY S1 大连机床厂 大连 S2 北京机床厂 北京 … …. P: 零件号 零件名 零件颜色 重量 Pno Pname Color Weight P1 螺母 红 12 P2 螺栓 兰 17 P3 螺丝刀 14 P4 P5 齿轮 绿 50 …
J: SPJ: 工程编号 工程名称 工程项目所在城市 JNO Jname City J1 海事大学图书馆 大连 J2 长春火车站 长春 … 供应商号 零件号 工程号 数量 Sno Pno Jno QTY S1 P1 J1 200 J2 300 S2 P2 100
S SPJ P J 求: 解: 1.供应工程“海事大学图书馆”零件名为“螺丝刀”的供应单位编号及名称(用从里到外执行的嵌套查询) 2. 供应工程“长春火车站”零件颜色为兰的单位编号及名称(用从外到里执行的嵌套查询) 解: 1. SELCT Sno,Sname FROM S WHERE Sno IN (SELECT Sno FROM SPJ WHERE PNO IN (SELECT Pno FROM P WHERE Pname=’螺丝刀’)AND JNO IN (SELECT Jno FROM J WHERE Jname=’海事大学图书馆’)); S SPJ P J
S P J SPJ 2.SELCT Sno,Sname FROM S WHERE EXISTS (SELECT * FROM P FROM J FROM SPJ WHERE Sno=S.Sno and Pno=P.Pno and SPJ.Jno=J.Jno and J.Jname=’长春火车站’ and P.color=’兰’))); S P J SPJ
练习 针对学生-课程体系,作SQL查询 1.列出各系的学生数(人数多的排在前面); 2.找出各科成绩均在85分以上(含)的学生的学号、姓名; 3.找出有三门课程的成绩在75分以下的学生的学号、姓名; 4.列出数据库成绩的前五名学生的学号、姓名、成绩。
答案 2. Select sname 3. SELECT sname 4. ????? from student where sno in (SELECT sno from sc as scz where not exists (select * from sc as scx where scx.sno=scz.sno and not exists from sc as scy where scy.sno=scz.sno and scy.cno=scx.cno and grade>85 ))); 3. SELECT sname FROM student WHERE sno in FROM sc WHERE grade<75 GROUP BY sno HAVING count(*)>=3); 4. ?????
3.3.5 集合查询(P114-P116) 集合操作,主要包括: 使用UNION将多个查询结果合并起来,系统会自动去掉重复的元组。 交操作(INTERSECT) 差操作(MINUS) 使用UNION将多个查询结果合并起来,系统会自动去掉重复的元组。 具体要求: 参加UNION操作的各结果表的列数必须相同 对应的数据项类型也必须相同 标准SQL中,没有直接提供: 集合交操作 集合差操作
3.3.5 集合查询 Cont.01 例:45查询计算机科学系的学生及年龄不大于19岁的学生。(见P114例45) SQL语句: SELECT * FROM student WHERE Sdept = ‘CS’ Union WHERE Sage<=19; 本查询实际上是求计算机科学系的所有学生与年龄不大于19岁的学生的并集。
§3.4 数据更新(P117-P121) 3.4.1 插入数据 3.4.2 修改数据 3.4.3 删除数据 3.4.4 一致性问题 SQL中数据更新,主要包括:插入数据、修改数据和删除数据。 3.4.1 插入数据 3.4.2 修改数据 3.4.3 删除数据 3.4.4 一致性问题
3.4.1 插入数据 3.4.1.1 插入单个元组 3.4.1.2 插入多行记录
3.4.1.1 插入单个元组 语法格式为: INSERT INTO <表名>[(<属性列1>[,<属性列2>…])] VALUES(<常量1>[<常量1>]…) 具体要求: INTO子句中没有出现的属性列,新记录在这些列上取空值。但表定义时说明NOT NULL的属性列不能取空值。 列名的排列顺序不一定要和表定义时的顺序一致。 当指定列名表时,VALUES子句值的排列顺序必须和列名表中的列名排列顺序一致,个数相等,数据类型一一对应 如果INTO子句中没有指明任何列名,则新插入的记录必须在每个属性列上均有值。
3.4.1.2 插入多行记录 用途:用于表间的拷贝,将一个表中的数据抽取数行插入另一表中。 实现途径:可以通过子查询来实现。 插入数据的命令语法格式为: INSERT INTO <表名> [(<属性列1>[,<属性列2>…])] 子查询
3.4.2 修改数据 3.4.2.1 修改某一个元组的值 3.4.2.2 修改多个元组的值 3.4.2.3 带子查询的修改语句 3.4.2 修改数据 SQL语言可以使用UPDATE语句对表中的一行或多行记录的某些列值进行修改,其语法格式为: UPDATE <表名> SET <列名>=<表达式> [,<列名>=<表达式>]… [WHERE <条件>] 3.4.2.1 修改某一个元组的值 3.4.2.2 修改多个元组的值 3.4.2.3 带子查询的修改语句
3.4.3 删除数据 3.4.3.1 删除某一个元组的值 3.4.3.2 删除多个元组的值 3.4.3.3 带子查询的删除语句 3.4.3 删除数据 使用DELETE语句可以删除表中的一行或多行记录,其语法格式为: DELETE FROM<表名> [WHERE <条件>] 3.4.3.1 删除某一个元组的值 3.4.3.2 删除多个元组的值 3.4.3.3 带子查询的删除语句
3.4.4更新操作与数据库的一致性问题 增、删、改操作只能对一个表操作。这会带来一些问题。 例如: 95019学生被删除后,有关其选课信息也应同时被删除; 然而,这只能通过两条语句进行。
§3.5 视图(P121-P129) 3.5.1 定义和删除视图 3.5.2 查询视图 3.5.3 更新视图 3.5.4 视图的作用 视图是关系数据库系统提供给用户的多种角度观察数据库中数据的重要机制。 视图是从一个或n个基本表(视图)导出的表,它与基本表不同,是一个虚表。 数据库中只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中。 视图在概念上与基本表等同,用户可以在视图上再定义视图,可以对视图进行查询、删除、更新等操作。 3.5.1 定义和删除视图 3.5.2 查询视图 3.5.3 更新视图 3.5.4 视图的作用
3.5.1 定义和删除视图 3.5.1.1 定义视图 3.5.1.2 删除视图
3.5.1.1 定义视图 定义视图使用语句CREATE VIEW,其语法格式为: 例1:建立信息系学生的视图。 3.5.1.1 定义视图 定义视图使用语句CREATE VIEW,其语法格式为: CREATE VIEW <视图名>[(<列名>[<列名>]…)] AS <子查询> [WITH CHECK OPTION] 例1:建立信息系学生的视图。 (行列子集视图,P112例2) CREATE VIEW IS_student AS SELECT Sno,Sname,Sage FROM Student WHERE Sdept=’IS’ WITH CHECK OPTION;
注意事项: WITH CHECK OPTION表示对视图进行UPDATE、INSERT和DELETE操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子查询中的条件表达式)。 组成视图的属性列名或者全部省略或者全部指定。 以下三种情况下,视图列名不可省略: (1)某个目标列不是单纯的属性名,是集函数或表达式 (2)多个连接时选出了几个同名列作为视图的字段 (3)需要在视图中为某个列启用新的更合适的名字 在子查询中,不许使用ORDER BY 子句和DISTINCT短语。如果需要排序,则可在视图定义后,对视图查询时再进行排序。
视图类型: 行列子集视图 带表达式的视图 分组视图 从单个基本表导出 并且只是去掉了基本表的某些行和某些列的视图 带虚拟列的视图 用带有集函数和GROUP BY子句的查询来定义的视图
行列子集视图:若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了码,称这类视图为行列子集视图。 行列子集视图:若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了码,称这类视图为行列子集视图。 带表达式的视图:视图中设置派生属性,虚拟列――带表达式的视图。 分组视图:由集函数和GROUP BY子句查询来定义视图。 可从一个表或多个表建立主视图,可以从视图中导出视图。 例2:建立信息系选了1号课程的学生的视图(P123例3) 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 Cno=’1’; 从多表建立主视图
例3:建立信息系选了1号课程且成绩在90分以上的学生的视图(P123例4) CREATE VIEW IS_S2 AS SELECT student.Sno,Sname,Grade FROM IS_S1 WHERE Grade>=90; 例4:定义一个反映学生出生年份的视图(P123例5) 。 CREATE VIEW BT_S (Sno,Sname,Sbirth) AS SELECT Sno,Sname,1996-Sage FROM student; 例5:将学生的学号及他的平均成绩定义为一个视图(P123例6) 。 CREATE VIEW S_Grade (Sno,Gavg) AS SELECT Sno,avg(Greade) FROM SC GROUP BY Sno; 从视图IS_S1 导出视图IS_S2 设置派生属性 (Derived Attribute) 的视图 设置派生属性 (Derived Attribute) 的视图
3.5.1.2 删除视图 视图定义后,可随时删除,删除视图的语法格式为: DROP VIEW <视图名> 视图删除后: 3.5.1.2 删除视图 视图定义后,可随时删除,删除视图的语法格式为: DROP VIEW <视图名> 视图删除后: 只会删除该视图在数据字典中的定义。 而与该视图有关的基本表中的数据不会受任何影响,由此视图导出的其他视图的定义不会删除,但已无任何意义。用户应该把这些视图删除。
3.5.2 查询视图 视图定义后,对视图的查询操作如同对基本表的查询操作一样。 DBMS查询视图的过程:视图消解 3.5.2 查询视图 视图定义后,对视图的查询操作如同对基本表的查询操作一样。 DBMS查询视图的过程:视图消解 首先进行有效性检查,检查查询的表、视图等是否存在。 如果存在,则从数据字典中取出视图的定义; 把定义中的子查询和用户的查询结合起来; 转换成等价的对基本表的查询。 然后再执行修正了的查询。 异 常 处 理 等价基本表查询转换 用户SQL查询 有效性检查 视图/表存在 数据词典 视图定义 基本表定义 是 否 执行修正查询
3.5.2 查询视图 Cont.01 例:在信息系学生的视图中找出年龄小于20岁的学生。 转换后: SELECT Sno,Sage FROM IS_student WHERE Sage<20; 转换后: FROM student WHERE Sdept=’IS’ and Sage<20;
3.5.3 更新视图 视图更新操作包括插入(INSERT) 、修改(UPDATE)和删除(DELETE)数据 3.5.3 更新视图 视图更新操作包括插入(INSERT) 、修改(UPDATE)和删除(DELETE)数据 由于视图是一张虚表,所以对视图的更新,最终实际上是转换成对基本表的更新,所以并不是所有的视图都是可以更新的 视图更新语法格式,同对基本表的更新操作一样 SQL对视图更新,必须遵循以下规则: ⑴从多个基本表通过连结操作导出的视图,不允许更新; ⑵对使用了分组、集函数操作的视图,则不允许进行更新操作; ⑶如果视图是从单个基本表通过投影、选择操作导出的,则允许进行更新操作,且语法同基本表。
例1:将信息系学生视图IS_student中学号为95002 的学生姓名改为“刘辰” (P126例1) UPDATE IS_student Set Sname=’ 刘辰’ WHERE Sno=’95002’; 例2:向信息系学生视图IS_student中插入一个新的学生记录,其中学号为95029 ,姓名为赵新,年龄20 (P126例2) 。 INSERT INTO IS_student VALUES (’95002’,’ 赵新’,20); 转换为对基本表的更新: INSERT INTO student VALUES (’95002’,’ 赵新’,20,’IS’); 例3:删除计算机系学生视图CS_S中学号为95029的记录(P127例3) DELETE FROM CS_S WHERE Sno=’95029’; 转换为对基本表的删除: DELETE FROM student WHERE Sno=’95029’ and Sdept=’CS’;
3.5.4 视图的作用 1. 简化查询操作 2. 使用户可以多角度看待同一数据 3. 保证数据的逻辑独立性 4. 利于数据保密
§3.6 数据控制(P129-P133) 安全性控制:完整性,并发性,恢复 数据控制指的是控制用户对数据的存储权利,是由DBA来决定的。但是,某个用户对某类数据具有何种权利,是政策问题,而不是技术问题。DBMS的功能就是保证这些决定的执行。 数据控制功能包括事务管理功能和数据保护功能,即: 数据库的恢复 并发控制 数据库的安全性控制 数据库的完整性控制 DBMS数据控制应具有如下功能: ⑴通过GRANT和REVOKE将授权通知系统,并存入数据字典; ⑵当用户提出请求时,根据授权情况,检查是否执行操作请求。
3.6.1 授权 SQL语言使用GRANT语句为用户授予操作权限,其语法格式为: 其中: [ON<对象类型><对象名>] TO <用户>[,<用户>]… [WITH GRANT OPTION]; 其中: PULBIC代表数据库中的全部用户。 WITH GRANT OPTION为可选项,指定后则允许被授权的用户将获得的某中权限再授予其他用户。 不同对象类型允许的操作权限(P130)
不同对象类型允许的操作权限 对象 对象类型 操作权限 属性列 TABLE SELECT,INSERT,UPDATE,DELETE,ALL PRIVILEGES 视 图 基本表 SELECT,INSERT,UPDATE,DELETE,ALTER,INDEX,ALL PRIVILEGES 数据库 DATABASE CREATETAB ALL PRIVILEGES:相应对象及对象类型所有权限的总和。
3.6.2 收回权限 数据库管理员可以使用REVOKE语句收回系统权限。 其语法格式为: [ON<对象类型><对象名>]… FROM <用户>[,<用户>]…;
§3.7 嵌入式SQL(P133-P148,可略/简述) 以上介绍的SQL语言:是作为独立语言在终端交互方式下使用的。 事务处理应用特点: 这是面向集合的描述性语言,是非过程性的。 大多数语句都是独立执行,与上下文无关的。 事务处理应用特点: 许多事务处理应用都是过程性的; 需要根据不同的条件来执行不同的任务; 因此单纯用SQL语言是很难实现这类应用的。 问题解决途径:为了解决这一问题,SQL语言提供了另一种使用方式,即: 将SQL语言嵌入到某种高级语言中使用; 利用高级语言的过程性结构来弥补SQL语言实现复杂应用方面的不足。 这种方式下使用的SQL语言称为嵌入式SQL(Embedded SQL),而嵌入SQL的高级语言称为主语言或宿主语言。
当然细节上会有许多差别,在程序设计的环境下,SQL语句要做某些必要的扩充。 作为独立语言在终端以交互的方式下使用; 也可嵌入到高级语言中使用。 在两种不同的使用方式下,SQL语言的语法结构基本上是一致的。 当然细节上会有许多差别,在程序设计的环境下,SQL语句要做某些必要的扩充。 在DBMS中,对宿主型数据库语言SQL采用两种方法处理: 1)第一种方法是采用预编译。 2)第二种方法是修改和扩充主语言使之能处理SQL语句。
若要采用第一种方法(预编译的方法)必须解决如下问题: 目前,采用最多的是预编译的方法,即: 由DBMS的预处理程序对源程序进行扫描,识别出SQL语句; 把他们转换为主语言调用语句,以使主语言编译程序能识别它; 最后由主语言的编译程序将整个源程序编译成目标码。 若要采用第一种方法(预编译的方法)必须解决如下问题: 区分主语言中嵌入的SQL语句; 主语言和SQL间的通信问题。 下面将分别介绍上述问题。
内容提要 3.7.1 区分SQL语句 3.7.2 嵌入式SQL与主语言之间的通信 3.7.3 程序实例
3.7.1 区分SQL语句 为了区分主语言与SQL语言,需要做以下工作: 例如,PL/1和C语言的引用格式为: 在所有的SQL语句前加前缀EXEC SQL; 而SQL的结束标志随主语言的不同而不同。 例如,PL/1和C语言的引用格式为: EXEC SQL <SQL语句>; 又如,COBOL语言的引用格式为: EXEC SQL <SQL语句> END- EXEC 嵌入式SQL语句按其作用不同可以分类为: 说明性语句; 可执行语句(细分为:数据定义、数据控制、数据操纵)。 嵌入式SQL语句在主语言中的定位:在宿主程序中 任何允许出现说明性高级语言语句的地方,都可以写说明性SQL语句; 任何允许出现可执行的高级语言语句的地方,都可以写可执行SQL语句。
3.7.2 嵌入式SQL与主语言之间的通信 将SQL嵌入到高级语言中混合编程,SQL语句与高级语言语句的分工: 高级语言语句负责控制程序流程。(是过程性的高级语言语句) 问题是,它们之间应该如何通信呢? 嵌入式SQL与主语言之间的通信采用三种方式: 1)SQL通信区(SQL Communication Area简称SQLCA) 2)主变量(Host Variable) 3)游标(Cursor)
1)SQL通信区 (SQL Communication Area简称SQLCA) 功能: 向主语言传递SQL语句执行的状态信息, 使主语言能够根据此信息控制程序流程。 过程: SQL语句执行后,系统要反馈给应用程序若干信息,主要包括描述系统当前工作状态和运行环境的各种数据。 这些信息将送到SQL通信区SQLCA中。 应用程序从SQLCA中取出这些状态信息,据此决定接下来执行的语句。
1)SQL通信区 (SQL Communication Area简称SQLCA) Cont.01 操作: SQLCA是一个数据结构,在应用程序中用EXEC SQL INCLUDE SQLCA加以定义。 SQLCA中有一个存放每次执行SQL语句后返回代码的变量SQLCODE。 应用程序每执行完一条SQL语句之后都应该测试一下SQLCODE的值,以了解该SQL语句执行情况并做相应处理。 如果SQLCODE等于预定义的常量SUCCESS,则表示SQL语句成功, 否则在SQLCODE中存放错误代码。
2)主变量 (Host Variable) 功能: 定义: 分类:主变量根据其作用的不同,分类如下---- 主语言向SQL语句提供参数主要通过主变量。 为了与SQL属性名相区别,需在主变量前加“:”。 定义: 嵌入式SQL语句中可以使用主语言的程序变量来输入或输出数据。 我们把SQL语句中使用的主语言程序变量简称为主变量。 分类:主变量根据其作用的不同,分类如下---- 输入主变量、 输出主变量、 输入又输出的主变量。
2)主变量 (Host Variable) Cont.01 其中: 输入主变量,由应用程序对其赋值,SQL语句引用; 输出主变量,由SQL语句对其赋值或设置状态信息,返回给应用程序。 利用输入主变量,可以完成以下功能: 可以指定向数据库中插入的数据, 可以将数据库中的数据修改为指定值, 可以指定执行的操作, 可以指定WHERE子句中的条件, 可以指定HAVING子句中的条件。 利用输出主变量,可以完成以下功能: 可以得到SQL语句的结果数据; 可以得到SQL语句的结果状态。
2)主变量 (Host Variable) Cont.02 操作: 所有主变量和指示变量必须在SQL语句BEGIN DECLARE SECTION与END DECLARE SECTION之间进行说明。 说明之后,主变量可以在SQL语句中任何一个能够使用表达式的地方出现。 为了与数据库对象名(表名、视图名、列名等)区别,SQL语句中的主变量名和指示变量前要加冒号(:)作为标志。 而在SQL语句之外,主变量和指示变量均可以直接引用,不必加冒号。
3)游标 (Cursor) SQL语言是面向集合的,一条SQL语句可产生或处理多条记录。 而主语言是面向记录的,一组主变量一次只能放一条记录。 所以,引入游标,通过移动游标指针来决定对获取哪一条记录。 游标 是系统为用户开设的一个数据缓冲区, 存放SQL语句的执行结果, 每个游标区都有一个名字。 用户可以通过游标 逐一获取记录, 并赋给主变量, 交由主语言进一步处理。
3.7.3 程序实例 嵌入式SQL的工作原理: SQL语句用主变量从主语言中接收执行参数,操纵数据库; SQL语句的执行状态由DBMS送至SQLCA中; 主语言程序从SQLCA中取出状态信息,据此决定下一步操作; 如果SQL语句从数据库中成功地检索出数据,则通过主变量传给主语言做进一步处理。 SQL语言和主语言的不同数据处理方式通过游标来协调。
3.7.3 程序实例 Cont.01 为了能够更好地理解上面的概念,下面给出带有嵌入式SQL的一小段C程序。 (具体见P136-137的程序实例) …………………… EXEC SQL INCLUDE SQLCA;……………………(1)定义SQL通信区 EXEC SQL BEGIN DECLARE SECTION…………(2)主变量说明开始 CHAR Sno(5); CHAR Cno(3); INT Grade; EXEC SQL END DECLARE SECTION;……………主变量说明结束
3.7.3 程序实例 Cont.02 main() { EXEC SQL DECLARE Cl CURSOR FOR…… … … … …(3)游标操作(定义游标) SELECT Sno,Cno,Grade FROM SC; /*从表中查询Sno,Cno,Grade*/ EXEC SQL OPEN Cl;…………………… … ……………(4)游标操作(打开游标) for(;;) EXEC SQL FETCH Cl INTO :Sno,:Cno,:Grade; … … ……(5)游标操作(推进游标 指针并将当前数据放入主变量) if(sqlca.sqlcode<>SUCCESS)……(6)利用SQLCA中的状态信息决定何时退出循环 Break; printf("Sno:%S,Cno:%S,Grade:%d'',:Sno,:Cno,:Grade); /*打印查询结果*/ } EXEC SQL CLOSE Cl (7) ……………… … …………………游标操作(关闭游标)
小 结 介绍了SQL的特点 数据定义 数据查询 数据更新 数据控制
作业 P148 1、2、3、4、5 P149 6、7、8、9、11、12