嵌入式SQL
简介
嵌入式SQL,指的是嵌入其他程序语言,如COBOL, C/C++, JAVA等语言中的SQL语句,简称为ESQL。与之对立的是交互式SQL,即直接在终端和数据库进行交互式访问,简称ISQL。
例如下面是一段C语言中嵌入式SQL的例子:
exec sql select count(*) into :host_var from customers;
使用ESQL时主要有以下几个部分:
- 声明:声明宿主变量。
- 条件处理:即异常处理,对访问出错的情况进行条件判断和处理。
- 连接数据库。
- 主体:ESQL语句实现要完成的操作。
- 断开数据库。
例如在上面的小例子中,host_var就是个宿主变量,前面加:来区分。这些宿主变量在ESQL语句中使用之前都需要经过特殊的声明。
声明
声明部分用来声明在ESQL语句中将要使用到的宿主变量。
来根据一个例子看一下声明的格式:
exec sql begin declare section;
char cust_id[5];
char cust_name[14];
float cust_discnt;
char user_name[20],user_pwd[20];
exec sql end declare section;
在声明的开始和结束都有说明。
条件处理
很重要的一个方法就是whenever语句,第二部分会详细说明。
连接数据库
sql99中连接数据库的语句:exec sql connect to @hocalhost (as connect_name) (user root); 或者也可以直接通过exec sql connect to default; 连接到默认数据库。
Oracle里连接数据库的语句是:exec sql connect to :user_name identified by :user_pwd;
断开数据库
sql99中断开数据库语句:exec sql disconnect connect_name; 或者exec sql disconnect current;
需要注意的是,在断开数据库连接之前,务必通过exec sql commit work;提交修改结果或者通过exec sql rollback work;撤销更改。
Oracle中则将提交或撤销和数据库断开合并为了一条语句:exec sql commit release;或者exec sql rollback release;
游标 Cursor
可以协助选择多行。其实是每次选择一行,但是可以滚动,类似迭代器。
使用步骤包括:
- 声明游标
- 打开游标
- 用游标取结果集
- 关闭游标
直接通过一个例子说明:
//声明游标
exec sql declare agent_dollars cursor for
select aid, sum(dollars)
from orders
where cid = :cust_id
group by aid;
//打开游标
exec sql open agent_dollars;
//使用游标取结果集
exec sql whenever not found goto finish;//条件控制
while(true){
exec sql fetch agent_dollars into :agent_id, :dollar_sum;
printf(agent_id,dollar_sum);
}
finish: exec sql close agent_dollars;//关闭游标
条件处理
通过whenever语句完成异常的判断和处理。whenever语句的格式是:exec sql whenever condition action; 其中condition有三种,而action有四种。
条件语句语句一旦声明,后面的直到遇到下一条条件处理语句,都是它的作用域。作用域中的每一条sql语句执行后都会按照条件进行检查。
三种条件:
- sqlerror:程序错误,可以终止程序的执行。
- not found:如果语句没有影响到任何行,就会触发。可以用来结束循环或者改变控制流。
- sqlwarning:值得注意的地方,警告。
四种动作:
- continue:继续执行下一条语句。
- goto lable:转到标记。
- stop:结束程序,撤销(rollback),并断开连接。
- Do function/break/continue。
whenever条件处理语句的作用域是按照语句写在代码里的位置决定的。
指示器变量可以用来代指空值(indicator=-1)。
通用ESQL语句
数据类型兼容表:
Basic sql | Oracle type | DB2/UDB type | C data type |
---|---|---|---|
char(n) | char(n) | char(n) | char arr[n+1] |
varchar(n) | varchar(n) | varchar(n) | char arr[n+1] |
smallint | smallint | smallint | short int |
integer, int | integer, int, number(10) | integer, int | int |
real | real | real | float |
double precision, float | double precision, number, float | double precision, double, float | double |
Select
exec sql
select ...
into ...
from ...
(where condition);
声明游标
exec sql
declare cursor_name cursor for subquery
(order by...)
(for read only/update(colname,...));
Delete
exec sql
delete from tablename (corr_name)
(where condition / where current of cursor_name);
corr_name指的是表的别名
Update
exec sql
update tablename (corr_name)
set column_name = expresion...
(where contion / current of cursor_name);
Insert
exec sql
insert into tablename (column_name ... )
values (....)
和ISQL里面的插入基本相同。
事务 Transaction
将一些语句打包成一个事务可以避免多个用户同时存取数据库的时候出现类似多线程数据不同步的错误。打包的事务一旦开始执行就不能被打断,直到整个事务执行完毕。
可以通过exec sql set transaction isolation level serializable;类似的语句声明事务的开始。
动态SQL
有三种类型:
- 立即执行:exec sql execute immediate :sqltext表示立即在此处执行sqltext中的sql语句。
- 准备好模板,需要的时候代入内容,然后执行:第一步是prepare handle from :sqltext; 第二步是execute handle using :host_var; 其中的sqltext通常是不完整的sql语句,其中一部分用一个?来代替。在执行第二部分的时候using后面的内容会被代入?处形成一个完整的sql语句,然后立即执行。
- 动态选择:describe语句和SQLDA。
另外还有一些高级概念。。。但是不是重点,就不赘述了。