DBMS_SQL package 学习
这个包提供了一种使用动态sql来访问数据库的方法。
第一步:打开游标
使用函数 function open_cursor return integer;
定义变量 Cur_1 integer; --返回的新游标的ID值
语句是Cur_1 := Dbms_Sql.Open_Cursor;
第二步:解析要执行的语句
使用过程procedure parse(c in integer, statement in varchar2, language_flag in integer);
语句是Dbms_Sql.Parse(Cur_1, ’sql语句’, Dbms_Sql.V7);
第三步:定义字段变量,其值对应于指定游标中某个位置元素的值(仅用于SELECT语句)
使用过程procedure define_column(c in integer, position in integer, column in number);
语句是Dbms_Sql.Define_Column(Cur_1, 1, column);
定义第一列为column,可重复定义多个列;
第四步:执行指定游标
使用过程function execute(c in integer) return integer;--返回行数
语句是Rows_1 := Dbms_Sql.EXECUTE(Cur_1);
第五步:从指定的游标中取出记录
使用过程function fetch_rows(c in integer) return integer;--返回行数
采用If Dbms_Sql.Fetch_Rows(Cur_1) > 0 then 判断是否取到数据了
然后返回游标中指定位置的元素,使用过程procedure column_value(c in integer, position in integer, value out number);
语句是Dbms_Sql.Column_Value(Cur_1, 1, column);
把游标中的第一列的值赋值给column,可重复赋值多个列;
要加上end if;
最后关闭游标
语句是Dbms_Sql.Close_Cursor(Cur_1);
通常运用DBMS_SQL包一般分为几步:
1. open cursor: 打开cursor
2. parse cursor:解析你要执行的
SQL语句
3. bind variable:如果要执行的SQL语句中包含变量,在此就需要绑定变量
4. execute:执行SQL语句
5. close cursor:在执行后关闭此cursor.
如果你还需要返回执行SQL的结果集,还需要使用define_column,define_array等方法。
下面根据不同情况进行详细展示:
在做展示之前,先准备一些基础数据
- create table demo (a number,b number,c number);
- begin
- for i in 1 .. 15 loop
- insert into demo
- values
- (round(dbms_random.value, 2) * 100,
- round(dbms_random.value, 2) * 100,
- round(dbms_random.value, 2) * 100);
- end loop;
- commit;
- end;
基础数据完成之后,下面开始对一些具体情况进行分析:
1.执行一般的select语句
首先先介绍最常用情况:
- create or replace procedure define_column(no in number) is
- cursor_name integer := dbms_sql.open_cursor;
- row_process integer;
- v_b number;
- begin
-
- dbms_sql.parse(cursor_name,
- 'select * from demo where a= :no',
- dbms_sql.native);
-
- dbms_sql.bind_variable(cursor_name, 'no', no);
- /*如果需要返回查询语句的结果,则必须在exec之前使用define_column函数定义返回字段;define_column函数的第一个参数是最初定义的cursor name,第二个参数是指需要返回的字段在查询结果中处于第几列,在此例中返回的字段是查询结果中的第二列,即b列;第三个参数就是接收返回结果需要的变量*/
- dbms_sql.define_column(cursor_name, 2, v_b);
-
- row_process := dbms_sql.execute(cursor_name);
- loop
- if dbms_sql.fetch_rows(cursor_name) > 0 then
-
- dbms_sql.column_value(cursor_name, 2, v_b);
- dbms_output.put_line('B is ' || v_b);
- else
- exit;
- end if;
- end loop;
-
- dbms_sql.close_cursor(cursor_name);
- exception
- when others then
- dbms_sql.close_cursor(cursor_name);
- end;
2.使用define_array方法得到查询结果
前面已经分析了如何使用define_column方法得到查询结果,但有时我们想要一次得到多行查询结果,此时我们就需要使用define_array方法,此方法常用于DML操作,稍后会有例子对此介绍,现在先来看一下如果使用define_array.
- create or replace procedure define_array is
- c NUMBER;
- d NUMBER;
- /*DBMS_SQL.NUMBER_TABLE类型实际就是type NUMBER_TABLE is table of number index by binary_integer;*/
- n_tab DBMS_SQL.NUMBER_TABLE;
- n_tab1 DBMS_SQL.NUMBER_TABLE;
- indx NUMBER := 1;
- BEGIN
- c := DBMS_SQL.OPEN_CURSOR;
- DBMS_SQL.PARSE(c,
- 'select * from demo where rownum<13 order by 1',
- DBMS_SQL.NATIVE);
- /*在此需要特别介绍一下define_array函数的第一个参数是已经打开的cursor名称, 第二个参数是指需要返回的字段在查询结果中处于第几列,第三个参数就是接收返回结果需要的变量,与define_column不同的是此变量是table,而不是普通的字段类型;第四个参数表示一次可以返回的行数;第五个参数是指n_tab的index从哪个数值开始,此数值是递增的.在此例中index是从1开始的,一次得到9行结果集,则有n_tab(1)到n_tab(9),如果循环再得到新的结果集,则index继续增长n_tab(10)....*/
- DBMS_SQL.DEFINE_ARRAY(c, 1, n_tab, 9, indx);
- DBMS_SQL.DEFINE_ARRAY(c, 2, n_tab1, 9, indx);
- d := DBMS_SQL.EXECUTE(c);
- loop
- d := DBMS_SQL.FETCH_ROWS(c);
- dbms_output.put_line('fetch rows is ' || d);
- EXIT WHEN d < 9;
- DBMS_SQL.COLUMN_VALUE(c, 1, n_tab);
- DBMS_SQL.COLUMN_VALUE(c, 2, n_tab1);
- for i in 1 .. d loop
- dbms_output.put_line(n_tab(i) || ',' || n_tab1(i));
- end loop;
- END LOOP;
- DBMS_SQL.CLOSE_CURSOR(c);
- EXCEPTION
- WHEN OTHERS THEN
- IF DBMS_SQL.IS_OPEN(c) THEN
- DBMS_SQL.CLOSE_CURSOR(c);
- END IF;
- END;
3.使用variable_value显示DML后的返回结果(单条记录)
以上我们介绍了如何使用DBMS_SQL包来处理数据查询,如果我们把查询语句更换成DML语句,则可以完成各种DML操作。
在PL/SQL中我们可以使用returning方法返回DML操作结果,在DBMS_SQL包中可不可以实现呢?答案当然是可以,用variable_value方法就可以实现。下面就分别用两个例子来展示如何实现,一个是返回单条记录,另一个是返回多条记录。
(1)返回单条记录
- procedure single_insert(c1 in number, c2 in number, r out number) is
-
- cursor_name number := dbms_sql.open_cursor;
- n number;
- begin
- dbms_sql.parse(cursor_name,
- 'insert into demo values (:a,:b) returning :a*:b into :r',
- dbms_sql.native);
- dbms_sql.bind_variable(cursor_name, 'a', c1);
- dbms_sql.bind_variable(cursor_name, 'b', c2);
- dbms_sql.bind_variable(cursor_name, 'r', r);
- n := dbms_sql.execute(cursor_name);
-
- dbms_sql.variable_value(cursor_name, 'r', r);
- dbms_output.put_line(r);
- dbms_sql.close_cursor(cursor_name);
- exception
- when others then
- dbms_sql.close_cursor(cursor_name);
- end;
(2)返回多条记录
结合define_array使用,可以更好的完成DML操作。
- create or replace package DBMS_SQL_DEMO as
-
- procedure multi_insert;
-
- end;
- /
-
- create or replace package body DBMS_SQL_DEMO as
-
- procedure multi_insert_priv(c1 in dbms_sql.Number_Table,
- c2 in dbms_sql.Number_Table,
- r out dbms_sql.Number_Table) is
-
- cursor_name number := dbms_sql.open_cursor;
- n number;
- begin
- dbms_sql.parse(cursor_name,
- 'insert into demo values (:a,:b) returning :a*:b into :r',
- dbms_sql.native);
-
- dbms_sql.bind_array(cursor_name, 'a', c1);
- dbms_sql.bind_array(cursor_name, 'b', c2);
- dbms_sql.bind_array(cursor_name, 'r', r);
- n := dbms_sql.execute(cursor_name);
-
- dbms_sql.variable_value(cursor_name, 'r', r);
- dbms_sql.close_cursor(cursor_name);
- exception
- when others then
- dbms_sql.close_cursor(cursor_name);
- end;
-
- procedure multi_insert is
- c1 dbms_sql.Number_Table;
- c2 dbms_sql.Number_Table;
- cursor_name number := dbms_sql.open_cursor;
- n number;
- r dbms_sql.Number_Table;
- indx number := 1;
- d number;
- begin
- dbms_sql.parse(cursor_name, 'select * from demo', dbms_sql.native);
- dbms_sql.define_array(cursor_name, 1, c1, 5, indx);
- dbms_sql.define_array(cursor_name, 2, c2, 5, indx);
- n := dbms_sql.execute(cursor_name);
- loop
- d := dbms_sql.fetch_rows(cursor_name);
- exit when d = 0;
- dbms_sql.column_value(cursor_name, 1, c1);
- dbms_sql.column_value(cursor_name, 2, c2);
- multi_insert_priv(c1, c2, r);
- for i in 1 .. r.count loop
- dbms_output.put_line(r(i));
- end loop;
- end loop;
- exception
- when others then
- dbms_sql.close_cursor(cursor_name);
- end;
-
- end;
- /