嵌入式SQL语言把SQL语言嵌入到某种高级语言中使用,利用高级语言的过程性结构来弥补SQL语言实现复杂应用方面的不足。这种方式下使用的SQL语言称为嵌入式SQL(Embedded SQL),而嵌入SQL的高级语言称为主语言或宿主语言。
1.1 嵌入式SQL的一般形式
对宿主型数据库语言SQL,DBMS可采用两种方法处理,一种是预编译,另一种是修改和扩充主语言使之能处理SQL语句。目前采用较多的是预编译的方法。即由DBMS的预处理程序对源程序进行扫描,识别出SQL语句。把它们转换成主语言调用语句,以使主语言编译程序能识别它,最后由主语言的编译程序将整个源程序编译成目标码。
在嵌入式SQL中,为了能够区分SQL语句与主语言语句,所有SQL语句都必须加前缀 EXEC SQL.。SQL语句的结束标志则随主语言的不同而不同。
例如在PL/1和C中以分号(;)结束;
EXEC SQL <SQL 语句> ;
在COBOL中以END-EXEC 结束;
EXEC SQL < SQL 语句> END-EXEC
例如 一条交互形式的SQL语句:DROP TABLE Student ;
嵌入到C程序中,应写成: EXEC SQL DROP TABLE Student ;
嵌入SQL语句根据其作用的不同,可分为可执行语句和说明性语句两种。可执行语句又分为数据定义,数据控制,数据操纵三种。
在宿主程序中,任何允许出现可执行的高级语言语句的地方,都可以写可执行SQL语句 ;任何允许出现说明型高级语言语句的地方,都可以写说明性SQL语句。
1.2 嵌入式SQL语句与主语言之间的通信
将SQL嵌入到高级语言中混合编程,SQL语句负责操纵数据库,高级语言语句负责控制程序流程。这时程序中会含有两种不同计算模型的语句,一种是描述性的面向集合的SQL语句,一种是过程性的高级语言语句,它们之间应该如何通信呢?
数据库工作单元与源程序工作单元之间的通信主要包括:
(1) 向主语言传递SQL语句的执行状态信息,使主语言能够据此信息控制程序流程,主要用SQL通信区(SQL Communication Area ,简称SQLCA)实现;
(2) 主语言向SQL语句提供参数,主要用主变量实现;
(3) 将SQL语句查询数据库的结果交主语言进一步处理,主要用主变量和游标(Cursor)实现。
一. SQL通信区
SQL语句执行后,系统要反馈给应用程序若干信息,主要包括描述系统当前工作状态和运行环境的各种数据。这些信息将送到SQL通信区SQLCA种。应用程序从SQLCA中取出这些状态信息,据此决定接下来执行的语句。
SQLCA是一个数据结构,在应用程序中用EXEC SQL INCLUDE SQLCA 加以定义。SQLCA中有一个存放每次执行SQL语句后返回代码的变量SQLCODE.。应用程序每执行完一条SQL语句之后都应该测试一下SQLCODE的值,以了解SQL语句执行情况并作相应处理。如果SQLCODE等于预定义的常量SUCCESS,则表示SQL语句成功,否则在SQLCODE中存放错误代码。
例如,在执行删除语句DELETE后,不同的执行情况SQLCA中有下列不同的信息:
l 成功删除,并有删除的行数(SQLCODE = SUCCESS)
l 无条件删除警告信息
l 违反数据保护规则,拒绝操作
l 没有满足条件的行,一行也没有删除
l 由于各种原因,执行出错
二. 主变量
嵌入式SQL语句中可以使用主语言的程序变量来输入或输出数据。我们把SQL语句中使用的主语言程序变量简称为主变量。
主变量根据其作用的不同,分为输入主变量和输出主变量。输入主变量由应用程序对其赋值,SQL语句引用;输出主变量由SQL语句对其赋值或设置状态信息,返回给应用程序。一个主变量有可能既是输入主变量又是输出主变量。利用输入主变量,可以指定向数据库中插入的数据,可以将数据库中的数据修改为指定值,可以指定执行的操作,可以指定WHERE 子句或HAVING子句中的条件。利用输出主变量,可以得到SQL语句的结果数据和状态。
所有主变量和指示变量(指示变量是一个整形变量,用来“指示“所指主变量的值或条件)必须在SQL语句BEGIN DECLARE SECTION 与END DECLARE SECTION 之间进行说明。说明之后,主变量可以在SQL语句中任何一个能够使用表达式的地方出现,为了与数据库对象名(表名,视图名,列名等)区别,SQL语句中的主变量名前要加冒号(:)作为标志。同样,SQL语句中的指示变量前也必须加冒号,并且要紧跟在所指主变量之后。而在SQL语句之外,主变量和指示变量均可以直接引用,不必加冒号。
三.游标
SQL语言与主语言具有不同的数据处理方式。SQL语言是面向集合的,一条SQL语句原则上可以产生或处理多条纪录。而主语言是面向纪录的,一组主变量一次只能存放一条纪录。所以仅使用主变量并不能完全满足SQL语句向应用程序输出数据的要求,为此嵌入式SQL引入了游标的概念,用游标来协调这两种不同的处理方式。游标是系统为用户可设的一个数据缓冲区,存放SQL语句的执行结果,每个游标区都有一个名字。用户可以通过游标逐一获取纪录。并赋给主变量,交由主语言进一步处理。
EXEC SQL INCLUDE SQLCA END-EXEC. ……………………………定义SQL通信区
01 ORA-WORKING-ITEMS.
EXEC SQL BEGIN DECLARE SECTION END-EXEC…….主变量说明开始
05 ORA-USER PIC X(01) VALUE '/'.
05 TBL-WSGTMMPE.
EXEC SQL INCLUDE WSGTMMPE.cpy END-EXEC.
05 S-WSGP83I.
EXEC SQL INCLUDE WSGQP83I.cpy END-EXEC.
05 KEY-SEC-CODE.
10 KEY-SEC-CODE1 PIC X(04).
10 KEY-SEC-CODE2 PIC X(01).
05 KEY-SEC-CD PIC X(14).
EXEC SQL END DECLARE SECTION END-EXEC. …..主变量说明结束
EXEC SQL DECLARE SEL_PLACE CURSOR FOR S END-EXEC. 游标操作(定义游标)
EXEC SQL OPEN SEL_PLACE END-EXEC. 游标操作 (打开游标)
EXEC SQL FETCH SEL_PLACE INTO …. 游标操作 (推进游标
指针并将当前数据放入主变量)
EXEC SQL CLOSE SEL_PLACE END-EXEC. 游标操作 (关闭游标)
1.3 不用游标的SQL语句
不用游标的SQL语句有:
l 说明性语句
l 数据定义语句
l 数据控制语句
l 查询结果为单纪录的SELECT语句
l 非CURRENT 形式的UPDATE 语句
l 非CURRENT 形式的DELETE 语句
l INSERT语句
所有的说明性语句及数据定义与控制语句都不需要使用游标。它们是嵌入式SQL中最简单的一类语句,不需要返回结果数据,也不需要使用主变量。在主语言中嵌入说明性语句及数据定义与控制语句,只要给语句加上前缀 EXEC SQL 和语句结束符即可。
INSERT语句也不需要使用游标,但通常需要使用主变量。
SELECT语句,UPDATE语句,DELETE 语句则要复杂些。
一. 说明性语句
说明性语句是专为在嵌入SQL中说明主变量等而设置的,主要有两条语句:
EXEC SQL BEGIN DECLARE SECTION; 和
EXEC SQL END DECLARE SECTION;
两条语句必须配对出现,相当于一个括号,两条语句中间是主变量的说明。
二. 数据定义语句
例1 建立一个”学生”表Student.
EXEC SQL CREATE TABLE Student (
Sno CHAR(5) NOT NULL UNIQUE,
Sname CHAR(20),
Ssex CHAR(1)’
Sage INT,
Sdept CHAR(15));
EXEC SQL DROP TABLE Student;
数据定义语句中不允许使用主变量。例如下列语句是错误的:
EXEC SQL DROP TABLE :table_name;
三. 数据控制语句
例2.把查询Student查询表权限授给用户U1.
EXEC SQL GRANT SELECT ON TABLE Student TO U1;
四. 查询结果为单纪录的SELECT语句
在嵌入式SQL中,查询结果为单纪录的SELECT语句需要用INTO 子句指定查询结果的存放地点。该语句的一般格式为:
EXEC SQL SELECT [ALL|DISTINCT]<目标列表达式>[,<目标列表达式>]……….
INTO <主变量>[<指示变量>][,<主变量>[<指示变量>]]……
FROM <表名或视图名> [,<表名或视图名>]。。。。。。
[WHERE <条件表达式>]
[GROUP BY <列名 1> [HAVING<条件表达式>]]
[ORDER BY <列名 2> [ASC|DESC]];
该语句对交互式SELECT语句的扩充就是多了一个INTO 子句。把 从数据库中找到的符合条件的纪录,放到INTO 子句指出的主变量中去。其他子句的含义不变。使用该语句需要注意以下几点:
1. INTO 子句,WHERE子句的条件表达式,HAVING短语的条件表达式中均可以使用主变量。
2. 查询返回的纪录中,可能某些列为空值 NULL。如果INTO 子句中主变量后面跟有指示变量,则当查询得出的某个数据项为空值时,系统会自动将相应主变量后面的指示变量置为负值,而不再向该主变量赋值,即主变量值仍为执行SQL语句之前的值。所以当指示变量值为负值时,不管主变量为何值,均应认为主变量值为NULL。指示变量只能用于INTO子句中。
3. 如果数据库中没有满足条件的纪录,则DBMS将SQLCODE的值置为100。
4. 如果查询结果实际上并不是单条纪录,而是多条纪录,则程序出错,DBMS会在SQLCA中返回错误信息。
例. 查询某个学生选修某门课程的成绩。假设已将要查询的学生的学号赋给了主变量givensno,将课程号赋给了主变量givencno.
EXEC SQL SELECT Sno,Cno,Grade
INTO :Hsno, :Hcno, :Hgrade:Gradeid
FROM SC
WHERE Sno=:givensno AND Cno=:givencno;
由于学生选修一门课后有可能没有参加考试,也就是说其成绩为空值,所以在INTO子句中加了值是变量Gradeid,用于指示主变量Hgrade是否为空值。执行此语句后,如果Gradeid小于0,则不论Hgrade为何值,均认为该学生成绩为空值。
五. 非CURRENT 形式的UPDATE语句
在UPDATE语句中,SET子句和WHERE子句中均可以使用主变量,其中SET子句中还可以使用指示变量。
例 将全体学生1号课程的考试成绩增加若干分。假设增加的分数已赋给主变量Raise.
EXEC SQL UPDATE SC
SET Grade= Grade+:Raise
WHERE Cno=’1’;
六. 非CURRENT 形式的DELETE语句
DELETE语句的WHERE子句中可以使用主变量指定删除条件。
例。某个学生退学了,现要将有关他的所有选课纪录删除掉。假设该学生的姓名已赋给主变量stdname.
EXEC SQL DELETE
FROM SC
WHERE Sno=
(SELECT Sno
FROM Student
WHERE Sname=:stdname);
另一种等价实现方法为:
EXEC SQL DELETE
FROM SC
WHERE :stdname=
( SELECT Sname
FROM Student
WHERE Student.Sno=SC.Sno );
第1种方法更直接,从而也更高效些。
七. INSERT 语句
INSERT语句的VALUES子句中可以使用主变量和指示变量。
1.4 使用游标的SQL语句
必须使用游标的SQL语句有:
l 查询结果为多条纪录的SELECT语句
l CURRENT 形式的UPDATE语句
l CURRENT 形式的DELETE语句
一. 查询结果为多条纪录的SELECT语句
一般情况下,SELECT语句查询结果都是多条纪录的,而高级语言一次只能处理一条纪录,因此需要用游标机制,将多条纪录一次一条送至宿主程序处理,从而把对集合的操作转换为对单个纪录的处理。
使用游标的步骤为:
1. 说明游标。用DECLARE语句为一条SELECT语句定义游标。DECLARE语句的一般形式为:
EXEC SQL DECLARE <游标名> CURSOR FOR <SELECT语句>;
其中SELECT语句可以是简单查询,也可以是复杂的连接查询和嵌套查询。定义游标仅仅是一条说明性的语句,这时DBMS并不执行SELECT语句。
2. 打开游标。用 OPEN语句将定义的游标打开。OPEN语句的一般形式为:
EXEC SQL OPEN<游标名>;
打开游标实际上是执行相应的SELECT语句,把查询结果取到缓冲区中。这时游标处于活动状态,指针指向查询结果集中第一条纪录。
3. 推进游标指针并取当前纪录。用FETCH语句把游标指针向前推进一条纪录,同时将缓冲区中的当前纪录取出来送至主变量供主语言进一步处理。FETCH语句的一般形式为:
EXEC SQL FETCH <游标名>
INTO <主变量>[<指示变量>][,<主变量>[<指示变量>]]。。。。。;
其中主变量必须与SELECT语句中的目标列表达式具有一一对应关系。
FETCH语句通常用在一个循环结构中,通过循环执行FETCH语句逐条取出结果集中的行进行处理。
4。关闭游标。用CLOSE 语句关闭游标,释放结果集占用的缓冲区及其他资源。CLOSE语句的一般形式为:
EXEC SQL CLOSE <游标名> ;
二. CURRENT形式的UPDATE语句和DELETE语句
UPDATE语句和DELETE语句都是集合操作,如果只想修改或删除其中某个纪录,则需要用带游标的SELECT语句查出所有满足条件的纪录,从中进一步找出要修改或删除的纪录,然后用CURRENT形式的UPDATE语句和DELETE语句修改或删除之。具体步骤是:
1. 用 DECLARE 语句说明游标。如果是为CURRENT形式的UPDATE语句做准备,则SELECT语句中要用
FOR UPDATE OF <列名>
用来指明检索出的数据在指定列是可修改的。如果是为CURRENT形式的DELETE语句做准备,则不必使用上述子句。
2. 用OPEN语句打开游标,把所有满足查询条件的记录从指定表取到缓冲区中。
3. 用FETCH语句推进游标指针,并把当前纪录从缓冲区中取出来送至主变量。
4. 检查该纪录是否是要修改或删除的纪录。如果是,则用UPDATE语句或DELETE语句修改或删除该纪录。这时UPDATE语句和DELETE语句中要用子句
WHERE CURRENT OF <游标名>
来表示修改或删除的是最后一次取出的纪录,即游标指针指向的纪录。
第3,4步通常用在一个循环结构中,通过循环执行FETCH语句,逐条取出结果集中的行进行判断和处理。
5.处理完毕用CLOSE语句关闭游标,释放结果集占用的缓冲区和其他资源。
动态 SQL简介
嵌入式SQL语句为编程提供了一定的灵活性,使用户可以在程序运行过程中根据实际需要输入WHERE 子句或HAVING子句中某些变量的值。这些SQL语句的共同特点是,语句中主变量的个数与数据类型在预编译时都是确定的,只有主变量的值是程序运行过程中动态输入的,称这类嵌入式SQL语句为静态SQL语句。
动态SQL方法允许在程序运行过程中临时“组装” SQL语句,主要有三种形式:
1. 语句可变。允许用户在程序运行时临时输入完整的SQL语句。
2. 条件可变。对于非查询语句,条件子具有一定的可变性。
对于查询语句,SELECT子句是确定的,即语句的输出是确定的,其他子句(如WHERE子句,HAVING短语)有一定的可变性,例如查询学生人数,可以是查询某个系的学生总人数,查询某个年龄段的学生人数等,这时SELECT子句的目标列表达式是确定的(COUNT(*)),但WHERE子句的条件是不确定的。
3. 数据库对象,查询条件均可变
对于查询语句,SELECT子句中的列名,FROM子句中的表名或视图名,WHERE子句和HAVING短语中的条件等均可由用户临时构造,即语句的输入和输出可能都是不确定的。
这几种动态形式几乎可覆盖所有的可变要求。为了实现上述三种可变形式,SQL提供了相应的语句,例如EXECUTE IMMEDIATE, PREPARE, EXECUTE, DESCRIBE
等。使用动态SQL技术更多的是涉及程序设计方面的知识,而不是SQL语言本身。
0 0