ESQL调oracle存储过程

ESQL采用的是预编译的模式,写sql相关的代码要用c风格的,c++风格的预编译过不了。

百度百科存储过程:“存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。”

首先你的有个oracle数据库以及装个oracle客户端,然后下载个sqldbx(免费)连数据库

先建一个测试用的表:

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;
View Code

SELECT * FROM STUDENT;

查到2条数据,接下来写一个插入一条数据的存储过程

 

CREATE OR REPLACE PROCEDURE  STD_PROC_INS  IS
BEGIN 
  INSERT INTO STUDENT VALUES(3, '王五', 'm', 60, 60);
  COMMIT;
END STD_PROC_INS;
View Code

这个存储过程的名称就是STD_PROC_INS,接下来写c代码去调用。

EXEC SQL EXECUTE
        BEGIN
        STD_PROC_INS();
        END;
END-EXEC;
View Code

一开始我忘记在END后面加;了,导致预编译一直报错。每调一次这个存储过程,表中就多一条记录。

接下来做一个查询返回一条记录的存储过程。

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;
View Code

对应的c代码:

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
}
View Code

调用这个函数,参数1是入参,输入要查询的人名,参数3和4就是查询出的结果值。

这表没有主键,所以同一个名字可以插入多条记录进去,当用名字查数据的时候,就会有多条数据。这个时候上面的存储过程执行就会报错,那么对返回结果是多条的,就得利用游标了。

 那么就得先声明一个游标my_cursor

1 CREATE OR REPLACE PACKAGE MYPACKAGE AS
2   TYPE my_cursor IS REF CURSOR;
3 END MYPACKAGE;
View Code

接下来在存储过程中使用这个游标

 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;
View Code

 写三个函数,一个取存储过程的值赋值给游标,一个是循环从游标内取值,一个是关闭游标

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打开游标执行结果处理;
}
View Code
 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 }
View Code
1 void b_test_querys_close()
2 {
3     // 关闭游标
4     EXEC SQL CLOSE :emp_cursor;
5     EXEC SQL FREE :emp_cursor;
6 }
View Code

以上代码的验证是在项目工程中,如果想从0开始写demo测试,需要做连接数据库的事情,可以参考以下两位作者的博文

http://www.cnblogs.com/liliu/archive/2011/06/22/2087546.html

http://blog.csdn.net/smallboy_5/article/details/3044255

posted @ 2017-09-22 10:49  超龄码农  阅读(353)  评论(0编辑  收藏  举报