将SQL嵌入到高级语言中混合编程,而程序中含有两种不同计算模型的语句,一种是描述性的面向集合的SQL语句,一种是过程性的高级语言语句。两种语言的分工是:SQL语句负责操纵数据库,高级语言语句负责控制程序流程。
它们之间的工作原理是:首先用SQL通信区(SQL Communication Area,简称SQLCA)向主语言传递SQL语句的执行状态信息,使主语言能够据此控制程序流程;在程序运行中,主语言向SQL语句提供参数,使用主变量(host variable)输入数据;同时,程序把SQL语句查询数据库的结果交主语言进一步处理,其中使用主变量和游标(cursor)向主语言输出数据,从而实现了SQL语言的过程化工作。
一、SQL通信区的作用和定义
SQL语句执行后,系统要反馈给应用程序若干信息,主要包括描述系统当前工作状态和运行环境的各种数据,这些信息将送到SQL通信区SQLCA中。应用程序从SQLCA中取出这些状态信息,据此决定接下来执行的语句。
SQLCA是一个数据结构。
定义语句: EXEC SQL INCLUDE SQLCA
SQLCA中有一个存放每次执行SQL语句后返回代码的变量SQLCODE。应用程序每执行完一条SQL 语句之后都应该测试一下SQLCODE的值,以了解该SQL语句执行情况并做相应处理。如果SQLCODE等于预定义的常量SUCCESS,则表示SQL语句成功,否则表示错误代码。
例如:在执行删除语句DELETE后,根据不同的执行情况,SQLCA中有下列不同的信息:
· 违反数据保护规则,操作拒绝
· 没有满足条件的行,一行也没有删除
· 成功删除,并有删除的行数(SQLCODE=SUCCESS)
· 无条件删除警告信息
· 由于各种原因,执行出错
二、主变量的作用与使用方法
(1)主变量的作用
嵌入式SQL语句中可以使用主语言的程序变量来输入或输出数据。我们把在SQL语句中使用的主语言程序变量简称为主变量。
主变量根据其作用的不同,分为输入主变量和输出主变量。
输入主变量由应用程序对其赋值,SQL语句引用;
输出主变量由SQL语句对其赋值或设置状态信息,返回给应用程序。
一个主变量有可能既是输入主变量又是输出主变量。利用输入主变量,我们可以指定向数据库中插入的数据,可以将数据库中的数据修改为指定值,可以指定执行的操作,可以指定WHERE子句或HAVING子句中的条件。利用输出主变量,我们可以得到SQL语句的结果数据和状态。
(2)指示变量
所谓指示变量是一个整型变量,用来“指示”所指主变量的值或条件。
一个主变量可以附带一个任选的指示变量(Indicator Variable)。输入主变量可以利用指示变量赋空值,输出主变量可以利用指示变量检测出是否空值,值是否被截断。
(3)主变量的说明语句
说明语句格式:
BEGIN DECLARE SECTION
<变量定义语句>
END DECLARE SECTION
*) 所有主变量和指示变量必须在上述格式中进行说明。说明之后,主变量可以在SQL语句中任何一个能够使用表达式的地方出现;
*) 为了与数据库对象名(表名、视图名、列名等)区别,SQL语句中的主变量名前要加冒号(:)作为标志。同样,SQL语句中的指示变量前也必须加冒号标志,并且要紧跟在所指主变量之后;而在SQL语句之外,主变量和指示变量均可以直接引用,不必加冒号。
三、游标
(1)概念
一般情况下,SELECT语句查询结果都是多条记录,而主语言是面向记录的,一组主变量一次只能存放一条记录。
所以仅使用主变量并不能完全满足SQL语句向应用程序输出数据的要求,为此嵌入式SQL引入了游标的概念,用游标来协调SQL语言与主语言这两种不同的处理方式。即以游标机制作为桥梁,将多条记录一次一条送至宿主程序处理,从而把对集合的操作转换为对单个记录的处理。
“游标”是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果。每个游标区都有一个名字。用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由主语言进一步处理。
(2)游标的使用方法
通常需要包括四个操作:
说明游标、打开游标、推进游标指针并取当前记录、关闭游标。
详细信息…
说明游标:
用DECLARE语句为一条SELECT语句定义游标。DECLARE语句的一般形式为:
EXEC SQL DECLARE <游标名> CURSOR FOR <SELECT语句>;
其中SELECT语句可以是简单查询,也可以是复杂的连接查询和嵌套查询。
定义游标仅仅是一条说明性语句,这时DBMS并不执行SELECT指定的查询操作。
打开游标:
用OPEN语句将上面定义的游标打开。OPEN语句的一般形式为:
EXEC SQL OPEN <游标名>;
打开游标实际上是执行相应的SELECT语句,把所有满足查询条件的记录从指定表取到缓冲区中。这时游标处于活动状态,指针指向查询结果集中第一条记录。
推进游标指针并取当前记录:
用FETCH语句把游标指针向前推进一条记录,同时将缓冲区中的当前记录取出来出来送至主变量供主语言进一步处理。FETCH语句的一般形式为:
EXEC SQL FETCH <游标名>
INTO <主变量>[<指示变量>][,<主变量>[<指示变量>]]...;
其中主变量必须与SELECT语句中的目标列表达式具有一一对应关系。
FETCH语句通常用在一个循环结构中,通过循环执行FETCH语句逐条取出结果集中的行进行处理。
为进一步方便用户处理数据,现在许多关系数据库管理系统对FETCH语句做了扩充,允许用户向任意方向以任意步长移动游标指针,而不仅仅是把游标指针向前推进一行了。
关闭游标:
用CLOSE语句关闭游标,释放结果集占用的缓冲区及其他资源。CLOSE语句的一般形式为:
EXEC SQL CLOSE <游标名>;
游标被关闭后,就不再和原来的查询结果集相联系。但被关闭的游标可以再次被打开,与新的查询结果相联系。
综合例子:给出带有嵌入式SQL的一小段C程序。
详细信息…
……
……
EXEC SQL INCLUDE SQLCA; ................(1) 定义SQL通信区
EXEC SQL BEGIN DECLARE SECTION; ........(2) 说明主变量
CHAR title_id(7);
CHAR title(81);
INT royalty;
EXEC SQL END DECLARE SECTION;
main()
{
EXEC SQL DECLARE C1 CURSOR FOR ...(3) 游标操作(定义游标)
SELECT tit_id, tit, roy FROM titles;
/* 从titles表中查询 tit_id, tit, roy */
EXEC SQL OPEN C1; ..............(4) 游标操作(打开游标)
for(;;)
{
EXEC SQL FETCH C1 INTO :title_id, :title, :royalty;
...........(5) 游标操作(推进游标指针)
(将当前数据放入主变量)
if (sqlca.sqlcode <> SUCCESS)
....(6) 利用SQLCA中的状态信息决定何时退出循环
break;
printf("Title ID: %s, Royalty: %d", :title_id, :royalty);
printf("Title: %s", :title);
/* 打印查询结果 */
}
EXEC SQL CLOSE C1; ........(7) 游标操作(关闭游标)
}