📄 esql-c资料(完全版)一_unix_操作系统_网络学院_天新网.htm
字号:
SELECT price INTO :price :price_nullflag FROM titles <BR>WHERE au_id
= "mc3026"<BR>其中,price是主变量,price_nullflag是指示符变量。<BR>使用指示符变量的语法为::
host_variable [[indicator] :
indicator_variable]。其中,indicator可以不写。针对宿主变量是输出宿主变量,还是输入宿主变量。指示符变量共分两种情况。<BR>情况1:同输出宿主变量一起使用,则indicator_varibale为:<BR>l-1。表示相应列值为NULL。表示主变量应该假设为NULL。(注意:宿主变量的实际值是一个无关值,不予考虑)。<BR>l0。表示非NULL值。该变量存放了非NULL的列值。<BR>l>0。表示宿主变量包含了列值的截断值。该指示变量存放了该列值的实际长度。
<P>下面是一个同输出宿主变量一起使用的指示变量的例子:<BR>exec sql begin declare
section;<BR>CS_CHAR id[6];<BR>CS_SMALLINT indic;<BR>CS_CHAR
pub_name[41];<BR>exec sql end declare section;<BR>exec sql select
pub_id into :id indicator :indic<BR>from titles where title<BR>like
"%Stress%";<BR>if (indic == -1)<BR>{<BR>printf("\npub_id is
null");<BR>}<BR>else<BR>{<BR>exec sql select pub_name into
:pub_name<BR>from publishers where pub_id =
:id;<BR>printf("\nPublisher: %s",
pub_name);<BR>情况2:同输入宿主变量一起使用,则indicator_varibale为:<BR>l-1。表示主变量应该假设为NULL。(注意:宿主变量的实际值是一个无关值,不予考虑)。应该将NULL赋值给相应列。<BR>l0。表示非NULL值。该变量存放了非NULL值。应该将宿主变量的值赋值给相应列。<BR>对于以下语句:<BR>EXEC
SQL SELECT price INTO :price :price_nullflag FROM titles <BR>WHERE
au_id =
"mc3026"<BR>如果不存在mc3026写的书,那么price_nullflag为-1,表示price为NULL;如果存在,则price为实际的价格。下面我们再看一个update的例子:<BR>EXEC
SQL UPDATE closeoutsale<BR>SET temp_price = :saleprice
:saleprice_null, listprice =
:oldprice;<BR>如果saleprice_null是-1,则上述语句等价为:<BR>EXEC SQL UPDATE
closeoutsale<BR>SET temp_price = null, listprice =
:oldprice;<BR>我们也可以在指示符变量前面加上“INDICATOR”关键字,表示后面的变量为指示符变量。如:<BR>EXEC
SQL UPDATE closeoutsale<BR>SET temp_price = :saleprice INDICATOR
:saleprice_null;<BR>指示符变量也是宿主变量,定义指示符变量同定义宿主变量一样。它应该是一个2个字节的整数(short或CS_SMALLINT)。<BR>2.3.2
连接数据库<BR>在程序中,使用CONNECT语句来连接数据库。该语句的完整语法为:<BR>exec sql connect :
user [identified by : password]<BR>[at : connection_name] [using :
server]<BR>[labelname labelname labelvalue labelvalue...]
其中,<BR>lserver为服务器名。如省略,则为本地服务器名。<BR>lconnection_name为连接名。可省略。如果你仅仅使用一个连接,那么无需指定连接名。可以使用SET
CONNECTION来使用不同的连接。<BR>luser为登录名。<BR>lpassword为密码。<BR>如:使用my_id用户和passes密码连接到SYBASE服务器。<BR>exec
sql begin declare section;<BR>CS_CHAR user[16];<BR>CS_CHAR
passwd[16];<BR>CS_CHAR server[BUFSIZ];<BR>exec sql end declare
section;<BR>strcpy(server,"SYBASE");<BR>strcpy(passwd,"passes");<BR>strcpy(user,
"my_id");<BR>exec sql connect :user identified by :passwd
using<BR>:server;<BR>请看下面这些例子来理解连接名的使用方法。<BR>...<BR>exec sql begin
declare section;<BR>CS_CHAR user[16];<BR>CS_CHAR
passwd[16];<BR>CS_CHAR name;<BR>CS_INT value, test;<BR>CS_CHAR
server_1[BUFSIZ];<BR>CS_CHAR server_2[BUFSIZ];<BR>exec sql end
declare section;<BR>...<BR>strcpy (server_1, "sybase1");<BR>strcpy
(server_2, "sybase2");<BR>strcpy(user, "my_id");<BR>strcpy(passwd,
"mypass");<BR>exec sql connect :user identified by :passwd<BR>at
connection_2 using :server_2;<BR>exec sql connect :user identified
by :passwd using<BR>:server_1;<BR>/*
下面这个语句使用了"server_1"的连接*/<BR>exec sql select royalty into :value from
authors<BR>where author = :name;<BR>if (value == test)<BR>{<BR>/*
下面这个语句使用了"connection_2"连接 */<BR>exec sql at connection_2 update
authors<BR>set column = :value*2<BR>where author = :name;
<P>在嵌入SQL语句中,使用DISCONNECT语句断开数据库的连接。其语法为:<BR>DISCONNECT
[connection_name | ALL |
CURRENT]<BR>其中,connection_name为连接名。ALL表示断开所有的连接。CURRENT表示断开当前连接。断开连接会回滚当前事务、删除临时表、关闭游标和释放锁等。<BR>2.3.3
数据的查询和修改<BR>可以使用SELECT
INTO语句查询数据,并将数据存放在主变量中。如:查询lastname为stringer的firstname信息。<BR>EXEC
SQL SELECT au_fname INTO :first_name<BR>from authors where au_lname
=
"stringer";<BR>使用DELETE语句删除数据。其语法类似于Transact-SQL中的DELETE语法。如:<BR>EXEC
SQL DELETE FROM authors WHERE au_lname =
'White'<BR>使用UPDATE语句可以更新数据。其语法类似Transact-SQL中的UPDATE语法。如:<BR>` EXEC
SQL UPDATE authors SET au_fname = 'Fred' WHERE au_lname =
'White'<BR>使用INSERT语句可以插入新数据。其语法就是Transact-SQL中的INSERT语法。如:<BR>EXEC
SQL INSERT INTO homesales (seller_name,
sale_price)<BR>real_estate('Jane Doe',
180000.00);<BR>多行数据的查询和修改请参见下一节——游标。<BR>2.3.4
游标的使用<BR>用嵌入式SQL语句查询数据分成两类情况。一类是单行结果,一类是多行结果。对于单行结果,可以使用SELECT
INTO语句;对于多行结果,你必须使用cursor(游标)来完成。游标(Cursor)是一个与SELECT语句相关联的符号名,它使用户可逐行访问由SQL
Server返回的结果集。先请看下面这个例子,这个例子的作用是逐行打印staff表的id、name、dept、
job、years、salary和comm的值。<BR>………..<BR>EXEC SQL DECLARE C1 CURSOR
FOR<BR>SELECT id, name, dept, job, years, salary, comm FROM
staff;<BR>EXEC SQL OPEN c1;<BR>while (SQLCODE == 0)<BR>{<BR>/*
SQLCODE will be zero if data is successfully fetched */
<P>EXEC SQL FETCH c1 INTO :id, :name, :dept, :job, :years, :salary,
:comm;<BR>if (SQLCODE == 0)<BR>printf("%4d %12s %10d %10s %2d %8d
%8d",<BR>id, name, dept, job, years, salary, comm);<BR>}<BR>EXEC SQL
CLOSE
c1;<BR>………<BR>从上例看出,你首先应该定义游标结果集,即定义该游标的SELECT语句返回的行的集合。然后,使用FETCH语句逐行处理。<BR>值得注意的是,嵌入SQL语句中的游标定义选项同Transact-SQL
中的游标定义选项有些不同。必须遵循嵌入SQL语句中的游标定义选项。<BR>1)、声明游标:<BR>如:EXEC SQL DECLARE
C1 CURSOR FOR<BR>SELECT id, name, dept, job, years, salary, comm
FROM staff;<BR>其中,C1是游标的名称。<BR>2)、打开游标<BR>如:EXEC SQL OPEN
c1;<BR>完整语法为:EXEC SQL OPEN 游标名 [USING 主变量名 | DESCRIPTOR
描述名]。关于动态OPEN游标的描述见第四节。<BR>3)、取一行值<BR>如:EXEC SQL FETCH c1 INTO :id,
:name, :dept, :job, :years, :salary,
:comm;<BR>关于动态FETCH语句见第四小节。<BR>4)、关闭游标<BR>如:EXEC SQL CLOSE
c1;<BR>关闭游标的同时,会释放由游标添加的锁和放弃未处理的数据。在关闭游标前,该游标必须已经声明和打开。另外,程序终止时,系统会自动关闭所有打开的游标。<BR>也可以使用UPDATE语句和DELETE语句来更新或删除由游标选择的当前行。使用DELETE语句删除当前游标所在的行数据的具体语法如下:<BR>DELETE
[FROM] {table_name | view_name} WHERE CURRENT OF
cursor_name<BR>其中,<BR>ltable_name是表名,该表必须是DECLARE
CURSOR中SELECT语句中的表。<BR>lview_name是视图名,该视图必须是DECLARE
CURSOR中SELECT语句中的视图。<BR>lcursor_name是游标名。<BR>请看下面这个例子,逐行显示firstname和lastname,询问用户是否删除该信息,如果回答“是”,那么删除当前行的数据。<BR>EXEC
SQL DECLARE c1 CURSOR FOR<BR>SELECT au_fname, au_lname FROM authors
;<BR>EXEC SQL OPEN c1;<BR>while (SQLCODE == 0)<BR>{<BR>EXEC SQL
FETCH c1 INTO :fname, :lname;<BR>if (SQLCODE ==
0)<BR>{<BR>printf("%12s %12s\n", fname, lname);<BR>printf("Delete?
");<BR>scanf("%c", &reply);<BR>if (reply == 'y')<BR>{<BR>EXEC
SQL DELETE FROM authors WHERE CURRENT OF c1;<BR>printf("delete
sqlcode= %d\n", SQLCODE(ca));<BR>}<BR>}<BR>}<BR>EXEC SQL CLOSE
c1;<BR>2.3.5
SQLCA<BR>DBMS是通过SQLCA(SQL通信区)向应用程序报告运行错误信息。SQLCA是一个含有错误变量和状态指示符的数据结构。通过检查SQLCA,应用程序能够检查出嵌入式SQL语句是否成功,并根据成功与否决定是否继续往下执行。预编译器自动会在嵌入SQL语句中插入SQLCA数据结构。在程序中可以使用EXEC
SQL INCLUDE
SQLCA,目的是告诉SQL预编译程序在该程序中包含一个SQL通信区。也可以不写,系统会自动加上SQLCA结构。<BR>下表是SQLCA结构中的变量和作用:
<P>变量 数据类型 作用
<P>sqlcaid char 包含“sqlca”的字符串<BR>sqlcabc long SQLCA的长度<BR>sqlcode
long 包含最近一次语句执行的返回代码<BR>sqlwarn[0] 到<BR>sqlwarn[7] char
警告标志。如果是“W”,那么表示有警报信息。<BR>sqlerrm.sqlerrmc[ ] char
错误信息。<BR>sqlerrm.sqlerrml long 错误信息的长度。<BR>sqlerrp char
检测错误或警告信息的过程。<BR>sqlerrd[6] long 警告或错误的详细信息。[2]中存放影响行的个数。
<P>下面仔细讲解几个重要的变量。<BR>1)、SQLCODE<BR>SQLCA结构中最重要的部分是SQLCODE变量。在执行每条嵌入式SQL语句时,DBMS在SQLCA中设置变量SQLCODE值,以指明语句的完成状态:<BR>1、0该语句成功执行,无任何错误或报警。<BR>2、<0
出现了严重错误。<BR>3、>0
出现了报警信息。<BR>4、100没有数据存在。在FETCH语句中,表示到达结果集的末尾。在UPDATE、<BR>DELETE、INSERT语句中,表示没有满足条件的数据。<BR>例:显示错误信息。<BR>printf("\nError
occurred: code %d.\n%s",<BR>sqlca.sqlcode,
sqlca.sqlerrm.sqlerrmc);<BR>在SYBASE SQL
SERVER中,也可以单独定义SQLCODE。如:<BR>long SQLCODE;<BR>exec sql open cursor
pub_id;<BR>while (SQLCODE == 0)<BR>{<BR>exec sql fetch pub_id into
:pub_name;<BR>…..
<P>2)、SQLSTATE<BR>SQLSTATE变量也是SQLCA结构中的成员。它同SQLCODE一样,都是返回错误信息。SQLSTATE是在SQLCODE之后产生的。这是因为,在制定SQL2标准之前,各个数据库厂商都采用SQLCODE变量来报告嵌入式SQL语句中的错误状态。但是,各个厂商没有采用标准的错误描述信息和错误值来报告相同的错误状态。所以,标准化组织增加了SQLSTATE变量,规定了通过SQLSTATE变量报告错误状态和各个错误代码。因此,目前使用SQLCODE的程序仍然有效,但也可用标准的SQLSTATE错误代码编写新程序。值得注意的是,Open
client emebeded
SQL/C11.1.x并不完全支持SQLSTATE。<BR>SQLSTATE是一个字符串参数。具体含义如下:
<P>值 作用
<P>00XXX 成功<BR>01XXX 警告<BR>02XXX 不存在数据<BR>其他值 错误
<P>2.3.6
WHENEVER<BR>在每条嵌入式SQL语句之后立即编写一条检查SQLCODE/SQLSTATE值的程序,是一件很繁琐的事情。为了简化错误处理,可以使用WHENEVER语句。该语句是SQL预编译程序的指示语句,而不是可执行语句。它通知预编译程序在每条可执行嵌入式SQL语句之后自动生成错误处理程序,并指定了错误处理操作。<BR>用户可以使用WHENEVER语句通知预编译程序去如何处理三种异常处理:<BR>lWHENEVER
SQLERROR
action:表示一旦sql语句执行时遇到错误信息,则执行action,action中包含了处理错误的代码(SQLCODE<0)。<BR>lWHENEVER
SQLWARNING
action:表示一旦sql语句执行时遇到警告信息,则执行aciton,即action中包含了处理警报的代码(SQLCODE=1)。<BR>lWHENEVER
NOT FOUND
action:表示一旦sql语句执行时没有找到相应的元组,则执行action,即action包含了处理没有查到内容的代码(SQLCODE=100)。<BR>针对上述三种异常处理,用户可以指定预编译程序采取以下三种行为(action):<BR>lWHENEVER
…GOTO:通知预编译程序产生一条转移语句。<BR>lWHENEVER…CONTINUE:通知预编译程序让程序的控制流转入到下一个主语言语句。<BR>lWHENEVER…CALL:通知预编译程序调用函数。<BR>其完整语法如下:<BR>WHENEVER
{SQLWARNING | SQLERROR | NOT FOUND} {CONTINUE | GOTO stmt_label |
CALL function()}<BR>例:WHENEVER的作用<BR>EXEC SQL WHENEVER sqlerror GOTO
errormessage1;<BR>EXEC SQL DELETE FROM homesales<BR>WHERE equity
< 10000;<BR>EXEC SQL DELETE FROM customerlist<BR>WHERE salary
< 40000;<BR>EXEC SQL WHENEVER sqlerror CONTINUE;<BR>EXEC SQL
UPDATE homesales<BR>SET equity = equity - loanvalue;<BR>EXEC SQL
WHENEVER sqlerror GOTO errormessage2;<BR>EXEC SQL INSERT INTO
homesales (seller_name, sale_price)<BR>real_estate('Jane Doe',
180000.00);<BR>.<BR>.<BR>.<BR>errormessage1:<BR>printf("SQL DELETE
error: %ld\n, sqlcode);<BR>exit();
<P>errormessage2:<BR>printf("SQL INSERT error: %ld\n,
sqlcode);<BR>exit();<BR>WHENEVER语句是预编译程序的指示语句。在上面这个例子中,由于第一个WHENEVER语句的作用,前面两个DELETE语句中任一语句内的一个错误会在errormessage1中形成一个转移指令。由于一个WHENEVER语句替代前面WHENEVER语句,所以,嵌入式UPDATE语句中的一个错误会直接转入下一个程序语句中。嵌入式INSERT语句中的一个错误会在errormessage2中产生一条转移指定。<BR>从上面例子看出,WHENEVER/CONTINUE语句的主要作用是取消先前的WHENEVER语句的作用。WHENEVER语句使得对嵌入式SQL错误的处理更加简便。应该在应用程序中普遍使用,而不是直接检查SQLCODE的值。<BR>2.3.7
批处理<BR>嵌入SQL也支持批处理。如:<BR>exec sql insert into TABLE1 values
(:val1)<BR>insert into TABLE2 values (:val2)<BR>insert into TABLE3
values (:val3);<BR>SYBASE SQL SERVER将在EXEC
SQL和“;”之间的所有T-SQL语句作为一个批来处理。在上例中,会将这3个语句作为一组来处理。<BR>2.3.8
事务<BR>SYBASE SQL
SERVER预编译器能够处理两种事务模式:ANSI/ISO事务模式和T-SQL模式。在T-SQL模式中,除非有begin
transaction外,每个语句都会做提交。可以在编译时设置事务模式。ANSI/ISO模式是系统的缺省模式。嵌入SQL的事务语法和T-SQL的事务语法是相同的。<BR>2.3.8.1
T-SQL事务模式<BR>1)、开始事务<BR>exec sql [at connect_name]<BR>begin
transaction [ transaction_name];<BR>2)、保存事务回滚点<BR>exec sql [at
connect_name]<BR>save transaction [
savepoint_name];<BR>3)、提交事务<BR>exec sql [at connect_name] commit
transaction<BR>[ transaction_name];<BR>4)、回滚事务<BR>exec sql [at
connect_name] rollback transaction<BR>[ savepoint_name |
transaction_name];<BR>2.3.8.2 ANSI/ISO事务模式<BR>该模式没有begin
transaction和save
transaction。在应用程序中,只要遇到以下语句,就表示事务开始:delete、insert、select、update、open和exec。当遇到commit
work或rollback
work,就表示事务结束。也就是说,commit和rollback表示当前事务结束,下一个事务开始。<BR>2.4动态SQL语句<BR>前一节中讲述的嵌入SQL语言都是静态SQL语言,即在编译时已经确定了引用的表和列。主变量不改变表和列信息。在上几节中,我们使用主变量改变查询参数,但是不能用主变量代替表名或列名。否则,系统报错。动态SQL语句就是来解决这个问题。<BR>动态SQL语句的目的是,不是在编译时确定SQL的表和列,而是让程序在运行时提供,并将SQL语句文本传给DBMS执行。静态SQL语句在编译时已经生成执行计划。而动态SQL语句,只有在执行时才产生执行计划。动态SQL语句首先执行PREPARE语句要求DBMS分析、确认和优化语句,并为其生成执行计划。DBMS还设置SQLCODE以表明语句中发现的错误。当程序执行完“PREPARE”语句后,就可以用EXECUTE语句执行执行计划,并设置SQLCODE,以表明完成状态。<BR>使用动态SQL,共分成四种方法:
<P>方法 支持的SQL语句 实现方法
<P>1 该语句内不包含宿主变量,该语句不是查询语句 execute immediate<BR>2 该语句内包含输入宿主变量
,该语句不是查询语句 prepare和execute<BR>3 包含已知数目的输入宿主变量或列的查询
prepare和fetch<BR>4 包含未知数目的输入宿主变量或列的查询 prepare和fetch,用描述符
<P>按照功能和处理上的划分,动态SQL应该分成两类来解释:动态修改和动态查询。方法1和方法2完成动态修改(参见2.4.1)。方法3和方法4完成了动态查询(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -