ESQL调oracle存储过程
ESQL采用的是预编译的模式,写sql相关的代码要用c风格的,c++风格的预编译过不了。
百度百科存储过程:“存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。”
首先你的有个oracle数据库以及装个oracle客户端,然后下载个sqldbx(免费)连数据库
先建一个测试用的表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CREATE TABLE student(id INTEGER, name VARCHAR2(20), sex CHAR(1), math NUMBER, english NUMBER); INSERT INTO student VALUES(1, '张三', 'm',80,90); INSERT INTO student VALUES(2, '小红', 'f',90,90); COMMIT;
SELECT * FROM STUDENT;
查到2条数据,接下来写一个插入一条数据的存储过程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CREATE OR REPLACE PROCEDURE STD_PROC_INS IS BEGIN INSERT INTO STUDENT VALUES(3, '王五', 'm', 60, 60); COMMIT; END STD_PROC_INS;
这个存储过程的名称就是STD_PROC_INS,接下来写c代码去调用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
EXEC SQL EXECUTE
BEGIN
STD_PROC_INS();
END;
END-EXEC;
一开始我忘记在END后面加;了,导致预编译一直报错。每调一次这个存储过程,表中就多一条记录。
接下来做一个查询返回一条记录的存储过程。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CREATE OR REPLACE PROCEDURE STD_PROC_QUERY(tmp_name IN VARCHAR2, tmp_math OUT NUMBER, tmp_eng OUT NUMBER) IS num_math NUMBER; num_eng NUMBER; BEGIN SELECT MATH, ENGLISH INTO num_math, num_eng FROM KS.STUDENT WHERE NAME = tmp_name; tmp_math := num_math; tmp_eng := num_eng; END;
对应的c代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void test_query(char *name, ST_ERR_MSG *err_msg, int *math, int *eng) { EXEC SQL BEGIN DECLARE SECTION; char mi_name[21] = {0}; int mo_math = 0; int mo_eng = 0; EXEC SQL END DECLARE SECTION; strncpy(mi_name, name, sizeof(mi_name)); EXEC SQL EXECUTE BEGIN STD_PROC_QUERY (:mi_name, :mo_math, :mo_eng); END; END-EXEC; *math = mo_math; *eng = mo_eng; // TODO处理下SQLCODE }
调用这个函数,参数1是入参,输入要查询的人名,参数3和4就是查询出的结果值。
这表没有主键,所以同一个名字可以插入多条记录进去,当用名字查数据的时候,就会有多条数据。这个时候上面的存储过程执行就会报错,那么对返回结果是多条的,就得利用游标了。
那么就得先声明一个游标my_cursor
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 CREATE OR REPLACE PACKAGE MYPACKAGE AS 2 TYPE my_cursor IS REF CURSOR; 3 END MYPACKAGE;
接下来在存储过程中使用这个游标
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 CREATE OR REPLACE PROCEDURE STD_PROC_QUERYS(tmp_name IN VARCHAR2, 2 P_CURSOR OUT mypackage.my_cursor) IS 3 num_1 NUMBER; 4 num_2 NUMBER; 5 6 BEGIN 7 num_1 := 0; 8 num_2 := 0; 9 OPEN P_CURSOR FOR 10 SELECT MATH, ENGLISH 11 INTO num_1, num_2 12 FROM STUDENT 13 WHERE NAME = tmp_name; 14 15 16 END STD_PROC_QUERYS;
写三个函数,一个取存储过程的值赋值给游标,一个是循环从游标内取值,一个是关闭游标
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
EXEC SQL BEGIN DECLARE SECTION; // 输入参数 SQL_CURSOR emp_cursor; EXEC SQL END DECLARE SECTION; void b_test_querys_open(char *name, ST_ERR_MSG *pstruerr_msg) { EXEC SQL BEGIN DECLARE SECTION; // 输入参数 char mi_name[12] = {0}; EXEC SQL END DECLARE SECTION; /* allocate cursor variable */ EXEC SQL ALLOCATE :emp_cursor; // 读输入参数 strncpy(mi_name, name, sizeof(mi_name)); EXEC SQL EXECUTE BEGIN STD_PROC_QUERYS(:mi_name, :emp_cursor); END; END-EXEC; //TODO打开游标执行结果处理; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void b_test_querys_fetch(ST_ERR_MSG *pstruerr_msg, int *i, int *j) 2 { 3 EXEC SQL BEGIN DECLARE SECTION; 4 int num_math = 0; 5 int num_eng = 0; 6 EXEC SQL END DECLARE SECTION; 7 8 EXEC SQL FETCH :emp_cursor 9 INTO 10 :num_math, :num_eng; 11 // 取出游标数据执行结果处理 12 if(SQLCODE == FOUND) 13 { 14 //TODO BSQL_OK_DEAL_STD; 15 } 16 else if(SQLCODE == NOTFOUND) 17 { 18 //TODO BSQL_ERR_DEAL_STD(""); 19 return; 20 } 21 else 22 { 23 //TODO BSQL_ERR_DEAL_STD("FETCH游标失败"); 24 return; 25 } 26 27 *i = num_math; 28 *j = num_eng; 29 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void b_test_querys_close() 2 { 3 // 关闭游标 4 EXEC SQL CLOSE :emp_cursor; 5 EXEC SQL FREE :emp_cursor; 6 }
以上代码的验证是在项目工程中,如果想从0开始写demo测试,需要做连接数据库的事情,可以参考以下两位作者的博文
http://www.cnblogs.com/liliu/archive/2011/06/22/2087546.html
http://blog.csdn.net/smallboy_5/article/details/3044255