• oracle 动态SQL


    动态SQL的书写:
    1.本地动态SQL(Native Dynamic SQL),用于建立和执行SQL语句, 使用EXECUTE IMMEDIATE命令来执行动态SQL语句。
    2.包DBMS_SQL也可用于执行动态SQL。

    CREATE OR REPLACE PROCEDURE  CreateTable(tablename VARCHAR2)
    IS
    BEGIN
        EXECUTE IMMEDIATE  'CREATE TABLE ' || tablespace || '(name VARCHAR(20),producer VARCHAR(30),price NUMBER)' ;
    END;
    --存储过程 CreateTable的输入参数是表的名字,根据表名的不同,动态创建不同的表。

    处理TCL语句:(事务控制语句)
    可以在PL/SQL代码中直接执行COOMMIT或ROLLBACK等事务控制语句,也可以在动态SQL中执行事务控制语句。

     1 DECLARE
     2 SQLstring VARCHAR2(1000);
     3 BEGIN
     4     SQLstring := 'COMMIT';
     5     EXECUTE IMMEDIATE 'INSERT INTO phone_info  VALUES(''N97'',''诺基亚'',400)';
     6     EXECUTE IMMEDIATE SQLstring;
     7 END;
     8 --查询执行结果:
     9 SELECT * FROM phone_info;
    10 
    11 NAME                 PRODUCER                            PRICE
    12 -------------------- ------------------------------ ----------
    13 N97                  诺基亚                                400

    处理DML语句
    普通的DML语句,不带占位符,不带USING子句:

     1 BEGIN
     2    EXECUTE IMMEDIATE 'INSERT INTO phone_info VALUES(''V800'',''中兴'',500)';
     3    COMMIT;
     4 END;
     5 --结果:
     6 SQL> SELECT * FROM phone_info;
     7 
     8 NAME                 PRODUCER                            PRICE
     9 -------------------- ------------------------------ ----------
    10 N97                  诺基亚                                400
    11 V800                 中兴                                  500
    12 
    13 已选择2行。

    有占位符的DML,使用USING子句传入值

     1 DECLARE
     2     v_phone_name  VARCHAR2(20) := 'C510c';
     3     v_producer VARCHAR2(20) := '爱立信';
     4     v_price NUMBER := 1000;
     5 BEGIN
     6     EXECUTE IMMEDIATE 'INSERT INTO phone_info VALUES(:a, :b,:c)' 
     7     USING v_phone_name,v_producer,v_price;
     8 COMMIT;
     9 END;
    10 
    11 SQL> SELECT * FROM phone_info;
    12 
    13 NAME                 PRODUCER                            PRICE
    14 -------------------- ------------------------------ ----------
    15 N97                  诺基亚                                400
    16 V800                 中兴                                  500
    17 C510c                爱立信                               1000

    执行有返回值的DML:

     1 DECLARE
     2     SQLstring VARCHAR2(1000);
     3     v_phone_name  VARCHAR2(20);
     4     v_producer VARCHAR2(20);
     5     v_price NUMBER := 400;
     6 BEGIN
     7     SQLstring := 'UPDATE phone_info SET price = 499 WHERE price = :a RETURNING name,producer,price INTO :b,:c,:d';
     8     EXECUTE IMMEDIATE SQLstring USING v_price RETURNING INTO v_phone_name,v_producer,v_price;
     9     COMMIT;
    10     DBMS_OUTPUT.PUT_LINE(v_phone_name||'  '||v_producer||'   '||v_price);
    11 END;
    1 --结果: price为400的已经更新为499.
    2 SQL> SELECT * FROM phone_info;
    3 
    4 NAME                 PRODUCER                            PRICE
    5 -------------------- ------------------------------ ----------
    6 N97                  诺基亚                                499
    7 V800                 中兴                                  500
    8 C510c                爱立信                               1000

    在动态SQL中调用存储过程或者函数:

     1 --定义procedure,
     2 CREATE  OR REPLACE  PROCEDURE  P_call (p1 IN VARCHAR2 := NULL ) AS
     3 BEGIN
     4     DBMS_OUTPUT.PUT_LINE(p1 || 'is from PROCEDURE P_call');
     5 END P_call;
     6 在动态SQL中调用procedure,
     7 BEGIN
     8     EXECUTE IMMEDIATE ' CALL P_call(''hihihi '')';
     9 END;
    10   4  /
    11 hihihi is from PROCEDURE P_call
    12 
    13 PL/SQL 过程已成功完成。

    在动态SQL中调用函数:

     1 CREATE OR REPLACE  FUNCTION F_call (p1 IN VARCHAR2)
     2 RETURN VARCHAR2 AS
     3 BEGIN
     4     RETURN p1 || ' is from FUNCTION F_call';
     5 END F_call;
     6 
     7 DECLARE 
     8 V_return VARCHAR2(50);
     9 functiong_Result VARCHAR2(50);
    10 BEGIN
    11     EXECUTE IMMEDIATE 'CALL F_call(''hello Daisy'') INTO :functiong_Result'
    12     USING OUT V_return;
    13 DBMS_OUTPUT.PUT_LINE(V_return);
    14 END;
    15   8  /
    16 hello Daisy is from FUNCTION F_call

    处理单行查询
    利用动态SQL,在PL/SQL中,可以对表进行查询,通过INTO子句,可以把查询结果保存在变量中。

    1 DECLARE 
    2     v_maxprice NUMBER;
    3     v_producer VARCHAR2(20) := '诺基亚';
    4 BEGIN
    5     EXECUTE IMMEDIATE 'SELECT max(price) FROM phone_info  WHERE producer= :a' 
    6     INTO v_maxprice     
    7     USING v_producer;
    8     dbms_output.put_line(v_maxprice);
    9 END;

    处理多行查询:
    两种方法,一是使用带有子句BULK COLLECT INTO的EXECUTE IMMEDIATE语句
    二是使用BULK COLLECT INTO 处理多行查询。
    BULK COLLECT可以将查询结果一次性的加载到集合中,而不是通过游标一条条地处理,这样的处理速度慢,可以在SELECT INTO 、FETCH INTO 、RETURNING INTO

    语句中使用BULK COLLECT,所有的INTO变量都必须是集合(COLLECTIONN)

     1 CREATE OR REPLACE  TYPE phone_type AS OBJECT
     2 (--定义新类型对象 
     3 name VARCHAR2(20),
     4 producer VARCHAR2(20),
     5 price NUMBER
     6 );
     7 
     8 CREATE  OR REPLACE  TYPE  phone_tab AS TABLE OF phone_type;--定义新类型
     9 
    10 DECLARE
    11     v_rec phone_tab;
    12 BEGIN
    13     EXECUTE IMMEDIATE 'SELECT phone_type (name,producer,price) FROM phone_info' BULK COLLECT INTO v_rec;
    14       FOR i IN v_rec.FIRST ..v_rec.LAST LOOP
    15         DBMS_OUTPUT.PUT_LINE(v_rec(i).name || '  ' ||v_rec(i).producer||'  ' ||v_rec(i).price);
    16     END LOOP;
    17 END;
     1 DECLARE 
     2     TYPE ref_type IS REF CURSOR;
     3     v_cursor  ref_type;
     4     v_record phone_info%ROWTYPE;
     5     sqlstring  VARCHAR2(200);
     6 BEGIN
     7     sqlstring := 'SELECT * FROM phone_info WHERE price > :p';
     8     OPEN v_cursor FOR sqlstring
     9         USING 450;
    10     LOOP
    11         FETCH v_cursor
    12             INTO  v_record;
    13     DBMS_OUTPUT.PUT_LINE('the record which >'||:p||' :  '||v_record.name || '     '||v_record.price );
    14     EXIT WHEN v_cursor%NOTFOUND;
    15     CLOSE v_cursor;
    16 END;
    17 --该procedure把手机价格大于500的打印出来。

    DBMS_SQL包提供一个接口,用于执行动态SQL(DDL和DML),DBMS_SQL定义了一个实体叫做游标ID,游标ID是一个PL/SQL整型数,通过游标ID可以对游标进行操作。
    包DBMS_SQL提供了一系列的过程和函数,用于协同执行动态SQL,这些函数和过程是:

     1 ---------------------------函数-------------------
     2 OPEN_CURSOR,打开一个动态游标,并返回一个整型;
     3 EXECUTE(c IN INTEGER),执行游标,并返回处理的函数(INSERTDELETE、UPDATE有意义);
     4 FETCH_ROWS(c IN INTEGER)循环对游标中取数据。
     5 ------------------------过程----------------------
     6 CLOSE_CURSOR(c IN OUT INTEGER) --关闭游标,
     7 PARSE(c IN INTEGER,statement IN VARCHAR2,language_flag IN INTEGER)--.对动态游标所提供的SQL语句进行解析,参数c表示有效,statement为SQL语句,language_flag为解析SQL语句所用的版本,一般是V6、NATIVE、V7。若被解析的是DDL语句,则解析完成后被立即执行。
     8 DEFINE_COLUMN(c IN INTEGER, position IN INTEGER,column ANY DATATYPE,[column_size IN INTEGER]),--定义从游标中选出的列,c为游标,position为对应动态SQL中的位置(从1开始),column为该值所对应的变量,可以为任何类型,column_size定义列的宽度,如果列的类型为字符型,必须定义宽度,这个语句只用于带有SELECT语句。
     9 COLUMN_VALUE(c IN INTEGER,position IN INTEGER,VALUE),--将所取得的游标数据赋值到相应的变量,c为游标,position为位置,VALUE则为对应的变量。
    10 BIND_VARIABLE(c IN INTEGER, name IN VARCHAR2,VALUE)--定义动态SQL语句(DML)中所对应字段的值。c为游标,name为字段名称,VALUE为字段的值。

    DBMS_SQL执行DDL语句的过程是:打开游标-->SQL语句解析-->关闭游标。

     1 CREATE OR REPLACE PROCEDURE  CreateTable(tablename VARCHAR2)
     2 IS
     3 SQL_string VARCHAR2(1000);--存放SQL语句
     4 V_cur integer;--存放游标
     5 BEGIN
     6 SQL_string := 'CREATE TABLE '||tablename || '(name VARCHAR2(20))';
     7 V_cur :=dbms_sql.open_cursor;
     8 dbms_sql.parse(V_cur,SQL_string,DBMS_SQL.NATIVE);
     9 dbms_sql.close_cursor(V_cur);
    10 END;
    11 SQL> EXECUTE CreateTable('MYTB');
    12 
    13 PL/SQL 过程已成功完成。
    14 
    15 已用时间:  00: 00: 00.17
    16 SQL> desc MYTB;
    17  名称
    18  -----------------------------------------
    19 ------------------------------------------
    20  NAME

    利用DBMS_SQL执行SELECT语句:

     1 DECLARE
     2     V_cursor NUMBER;
     3     SQLstring VARCHAR2(1000);
     4     v_phone_name  VARCHAR2(20);
     5     v_producer VARCHAR2(20);
     6     v_price NUMBER := 400;
     7     v_count INT;
     8 BEGIN
     9     SQLstring := 'SELECT name,producer,price FROM phone_info WHERE price >:p';
    10     V_cursor := dbms_sql.open_cursor;--open the cursor;
    11     dbms_sql.parse(V_cursor,SQLstring,dbms_sql.native);--parse the sql statement;
    12     dbms_sql.bind_variable(V_cursor,'p',v_price);
    13     
    14     dbms_sql.define_column(v_cursor,1,v_phone_name,20);
    15     dbms_sql.define_column(v_cursor,2,v_producer,20);
    16     dbms_sql.define_column(v_cursor,3,v_price);
    17     v_count := dbms_sql.EXECUTE(V_cursor);
    18 
    19     LOOP
    20         EXIT WHEN DBMS_sql.fetch_rows(V_cursor) <= 0;
    21         dbms_sql.column_value(V_cursor,1,v_phone_name);
    22         dbms_sql.column_value(V_cursor,2,v_producer);
    23         dbms_sql.column_value(V_cursor,3,v_price);
    24         dbms_output.put_line(v_phone_name|| '   '||v_producer ||'  '||v_price);
    25     END LOOP;
    26     dbms_sql.close_cursor(V_cursor);
    27 END;
    28 --把price >400的都打印出来了。

    利用DBMS_SQL执行DML语句
    过程:打开游标--》解析动态SQL--》绑定输入参数—》执行动态SQL--》关闭游标。

     1 DECLARE 
     2     v_cursor NUMBER;
     3     sqlstring VARCHAR2(200);
     4     v_phone_name VARCHAR2(20);
     5     v_producer VARCHAR2(20);
     6     v_price NUMBER;
     7     v_count    INT;
     8 BEGIN
     9     sqlstring := 'INSERT INTO phone_info VALUES(:a,:b,:c)'; ---:a,:b,:c
    10     v_phone_name := 'iphone';
    11     v_producer := 'APPLE';
    12     v_price := 3999;
    13     v_cursor :=dbms_sql.open_cursor;
    14     dbms_sql.parse(v_cursor,sqlstring,dbms_sql.native);
    15     dbms_sql.bind_variable (v_cursor,':a',v_phone_name);
    16     dbms_sql.bind_variable (v_cursor,':b',v_producer);
    17     dbms_sql.bind_variable (v_cursor,':c',v_price);
    18     v_count := dbms_sql.EXECUTE(v_cursor);
    19     dbms_sql.close_cursor(v_cursor);
    20     dbms_output.put_line('INSERT '||to_char(v_count)||'  row');
    21     COMMIT;
    22 END;
  • 相关阅读:
    重装系统之后应装软件
    中文乱码解决方案
    买电脑需要考虑的电脑配置
    JavaBean个人总结
    Servlet个人总结
    web.xml详解
    默认软件
    Eclipse导入项目
    Eclipse插件安装
    Tomcat详解
  • 原文地址:https://www.cnblogs.com/happinessqi/p/3352820.html
Copyright © 2020-2023  润新知