3)、主变量和NULL
大多数程序设计语言(如C)都不支持NULL。所以对NULL的处理,一定要在SQL中完成。我们可以使用主机指示符变量(host indicator variable)来解决这个问题。在嵌入式SQL语句中,主变量和指示符变量共同规定一个单独的SQL类型值。如:
EXEC SQL SELECT price INTO :price :price_nullflag FROM titles
WHERE au_id = \
其中,price是主变量,price_nullflag是指示符变量。
使用指示符变量的语法为:: host_variable [[indicator] : indicator_variable]。其中,indicator可以不写。针对宿主变量是输出宿主变量,还是输入宿主变量。指示符变量共分两种情况。
情况1:同输出宿主变量一起使用,则indicator_varibale为:
? -1。表示相应列值为NULL。表示主变量应该假设为NULL。(注意:宿主变量的
实际值是一个无关值,不予考虑)。
? 0。表示非NULL值。该变量存放了非NULL的列值。
? >0。表示宿主变量包含了列值的截断值。该指示变量存放了该列值的实际长度。
下面是一个同输出宿主变量一起使用的指示变量的例子:
exec sql begin declare section; CS_CHAR id[6]; CS_SMALLINT indic; CS_CHAR pub_name[41];
exec sql end declare section;
exec sql select pub_id into :id indicator :indic from titles where title like \if (indic == -1) {
printf(\} else {
exec sql select pub_name into :pub_name from publishers where pub_id = :id; printf(\
情况2:同输入宿主变量一起使用,则indicator_varibale为:
? -1。表示主变量应该假设为NULL。(注意:宿主变量的实际值是一个无关值,不
予考虑)。应该将NULL赋值给相应列。
? 0。表示非NULL值。该变量存放了非NULL值。应该将宿主变量的值赋值给相应
列。
对于以下语句:
EXEC SQL SELECT price INTO :price :price_nullflag FROM titles
WHERE au_id = \
如果不存在mc3026写的书,那么price_nullflag为-1,表示price为NULL;如果存在,
11
则price为实际的价格。下面我们再看一个update的例子:
EXEC SQL UPDATE closeoutsale SET temp_price = :saleprice :saleprice_null, listprice = :oldprice; 如果saleprice_null是-1,则上述语句等价为:
EXEC SQL UPDATE closeoutsale SET temp_price = null, listprice = :oldprice;
我们也可以在指示符变量前面加上“INDICATOR”关键字,表示后面的变量为指示符变量。如:
EXEC SQL UPDATE closeoutsale SET temp_price = :saleprice INDICATOR :saleprice_null; 指示符变量也是宿主变量,定义指示符变量同定义宿主变量一样。它应该是一个2个字节的整数(short或CS_SMALLINT)。
2.3.2 连接数据库
在程序中,使用CONNECT语句来连接数据库。该语句的完整语法为:
exec sql connect : user [identified by : password] [at : connection_name] [using : server]
[labelname labelname labelvalue labelvalue...] 其中,
? server为服务器名。如省略,则为本地服务器名。
? connection_name为连接名。可省略。如果你仅仅使用一个连接,那么无需指定连接名。
可以使用SET CONNECTION来使用不同的连接。 ? user为登录名。 ? password为密码。
如:使用my_id用户和passes密码连接到SYBASE服务器。
exec sql begin declare section; CS_CHAR user[16]; CS_CHAR passwd[16]; CS_CHAR server[BUFSIZ]; exec sql end declare section; strcpy(server,\strcpy(passwd,\strcpy(user, \
exec sql connect :user identified by :passwd using
:server;
请看下面这些例子来理解连接名的使用方法。
...
exec sql begin declare section; CS_CHAR user[16]; CS_CHAR passwd[16]; CS_CHAR name; CS_INT value, test; CS_CHAR server_1[BUFSIZ]; CS_CHAR server_2[BUFSIZ];
12
exec sql end declare section; ...
strcpy (server_1, \strcpy (server_2, \strcpy(user, \strcpy(passwd, \
exec sql connect :user identified by :passwd at connection_2 using :server_2;
exec sql connect :user identified by :passwd using :server_1;
/* 下面这个语句使用了\的连接*/
exec sql select royalty into :value from authors where author = :name; if (value == test) {
/* 下面这个语句使用了\连接 */ exec sql at connection_2 update authors set column = :value*2 where author = :name;
在嵌入SQL语句中,使用DISCONNECT语句断开数据库的连接。其语法为:
DISCONNECT [connection_name | ALL | CURRENT]
其中,connection_name为连接名。ALL表示断开所有的连接。CURRENT表示断开当前连接。断开连接会回滚当前事务、删除临时表、关闭游标和释放锁等。
2.3.3 数据的查询和修改
可以使用SELECT INTO语句查询数据,并将数据存放在主变量中。如:查询lastname为stringer的firstname信息。 EXEC SQL SELECT au_fname INTO :first_name from authors where au_lname = \
使用DELETE语句删除数据。其语法类似于Transact-SQL中的DELETE语法。如: EXEC SQL DELETE FROM authors WHERE au_lname = 'White'
使用UPDATE语句可以更新数据。其语法类似Transact-SQL中的UPDATE语法。如: ` EXEC SQL UPDATE authors SET au_fname = 'Fred' WHERE au_lname = 'White' 使用INSERT语句可以插入新数据。其语法就是Transact-SQL中的INSERT语法。如:
EXEC SQL INSERT INTO homesales (seller_name, sale_price) real_estate('Jane Doe', 180000.00); 多行数据的查询和修改请参见下一节——游标。
2.3.4 游标的使用(2011.7.8~17:00)
用嵌入式SQL语句查询数据分成两类情况。一类是单行结果,一类是多行结果。对于
13
单行结果,可以使用SELECT INTO语句;对于多行结果,你必须使用cursor(游标)来完成。游标(Cursor)是一个与SELECT语句相关联的符号名,它使用户可逐行访问由SQL Server返回的结果集。先请看下面这个例子,这个例子的作用是逐行打印staff表的id、name、dept、 job、years、salary和comm的值。 ………..
EXEC SQL DECLARE C1 CURSOR FOR
SELECT id, name, dept, job, years, salary, comm FROM staff; EXEC SQL OPEN c1; while (SQLCODE == 0) {
/* SQLCODE will be zero if data is successfully fetched */
EXEC SQL FETCH c1 INTO :id, :name, :dept, :job, :years, :salary, :comm; if (SQLCODE == 0)
printf(\ id, name, dept, job, years, salary, comm); }
EXEC SQL CLOSE c1; ………
从上例看出,你首先应该定义游标结果集,即定义该游标的SELECT语句返回的行的集合。然后,使用FETCH语句逐行处理。
值得注意的是,嵌入SQL语句中的游标定义选项同Transact-SQL 中的游标定义选项有些不同。必须遵循嵌入SQL语句中的游标定义选项。 1)、声明游标:
如:EXEC SQL DECLARE C1 CURSOR FOR
SELECT id, name, dept, job, years, salary, comm FROM staff; 其中,C1是游标的名称。 2)、打开游标
如:EXEC SQL OPEN c1;
完整语法为:EXEC SQL OPEN 游标名 [USING 主变量名 | DESCRIPTOR 描述名]。关于动态OPEN游标的描述见第四节。 3)、取一行值
如:EXEC SQL FETCH c1 INTO :id, :name, :dept, :job, :years, :salary, :comm; 关于动态FETCH语句见第四小节。 4)、关闭游标
如:EXEC SQL CLOSE c1;
关闭游标的同时,会释放由游标添加的锁和放弃未处理的数据。在关闭游标前,该游标必须已经声明和打开。另外,程序终止时,系统会自动关闭所有打开的游标。
也可以使用UPDATE语句和DELETE语句来更新或删除由游标选择的当前行。使用DELETE语句删除当前游标所在的行数据的具体语法如下:
DELETE [FROM] {table_name | view_name} WHERE CURRENT OF cursor_name 其中,
? table_name是表名,该表必须是DECLARE CURSOR中SELECT语句中的表。
? view_name是视图名,该视图必须是DECLARE CURSOR中SELECT语句中的视图。
14
? cursor_name是游标名。
请看下面这个例子,逐行显示firstname和lastname,询问用户是否删除该信息,如果回答“是”,那么删除当前行的数据。 EXEC SQL DECLARE c1 CURSOR FOR
SELECT au_fname, au_lname FROM authors ; EXEC SQL OPEN c1; while (SQLCODE == 0) {
EXEC SQL FETCH c1 INTO :fname, :lname; if (SQLCODE == 0) {
printf(\ printf(\ scanf(\ if (reply == 'y') {
EXEC SQL DELETE FROM authors WHERE CURRENT OF c1; printf(\ } } }
EXEC SQL CLOSE c1;
2.3.5 SQLCA
DBMS是通过SQLCA(SQL通信区)向应用程序报告运行错误信息。SQLCA是一个含有错误变量和状态指示符的数据结构。通过检查SQLCA,应用程序能够检查出嵌入式SQL语句是否成功,并根据成功与否决定是否继续往下执行。预编译器自动会在嵌入SQL语句中插入SQLCA数据结构。在程序中可以使用EXEC SQL INCLUDE SQLCA,目的是告诉SQL预编译程序在该程序中包含一个SQL通信区。也可以不写,系统会自动加上SQLCA结构。
下表是SQLCA结构中的变量和作用: 变量 数据类型 作用 sqlcaid char 包含“sqlca”的字符串 sqlcabc long SQLCA的长度
sqlcode long 包含最近一次语句执行的返回代码 sqlwarn[0] 到
sqlwarn[7] char 警告标志。如果是“W”,那么表示有警报信息。 sqlerrm.sqlerrmc[ ] char 错误信息。
sqlerrm.sqlerrml long 错误信息的长度。
sqlerrp char 检测错误或警告信息的过程。
sqlerrd[6] long 警告或错误的详细信息。[2]中存放影响行的个数。
15