Oracle基础 动态SQL语句

系统 1702 0
原文: Oracle基础 动态SQL语句

一、静态SQL和动态SQL的概念。

1、静态SQL

  静态SQL是我们常用的使用SQL语句的方式,就是编写PL/SQL时,SQL语句已经编写好了。因为静态SQL是在编写程序时就确定了,我们只能使用SQL中的DML和事务控制语句,但是DDL语句,以及会话控制语句却不能再PL/SQL中直接使用,如动态创建表或者某个不确定的操作时,这就需要动态SQL来实现。

  2、 动态SQL

  动态SQL是指在PL/SQL编译时SQL语句是不确定的,如根据用户输入的参数的不同来执行不同的操作。编译程序对动态语句部分不进行处理,只是在程序运行时动态创建语句,对语句进行分析,病执行该语句。

  静态SQL的优势是性能较高,但不灵活。动态SQL的优势是灵活,缺点是性能稍差。

 

二、动态创建DML、DDL的SQL语句。

  动态创建SQL有一下几类:

  1、DDL语句、DCL语句、非查询的DML语句、单行查询的SELECT语句,这类可以使用EXECUTE IMMEDIATE语句执行。

  2、多行查询的SELECT语句可以使用游标来实现。

  3、通过DBMS_SQL程序包实现。

  下面来介绍以上3种情况:

 

1、使用EXECUTE IMMEDIATE语句处理相关语句:

  语法:

  EXECUTE IMMEDIATE dynamic_sql_string

  [into define_variable_list]

  [using bind_argument_list];

  例:  

    动态创建表t1
  
      
        --
      
      
        处理DDL、DCL语句,根据用户输入的表明及字段名动态创建表t1
      
      
        DECLARE
      
      
        

  tablename 
      
      
        VARCHAR2
      
      (
      
        20
      
      );        
      
        --
      
      
        表名
      
      

    field1 
      
        VARCHAR2
      
      (
      
        20
      
      );           
      
        --
      
      
        字段1名称
      
      

    datatype1 
      
        VARCHAR2
      
      (
      
        20
      
      );        
      
        --
      
      
        字段1类型
      
      

    field2 
      
        VARCHAR2
      
      (
      
        20
      
      );           
      
        --
      
      
        字段2名称
      
      

    datatype2 
      
        VARCHAR2
      
      (
      
        20
      
      );        
      
        --
      
      
        字段2类型
      
      

    str_sql 
      
        VARCHAR2
      
      (
      
        500
      
      );         
      
        --
      
      
        拼接SQL语句的字符串
      
      
        BEGIN
      
      
        

    tablename :
      
      
        =
      
      
        '
      
      
        t1
      
      
        '
      
      
        ;

    field1:
      
      
        =
      
      
        '
      
      
        id
      
      
        '
      
      
        ;

    datatype1:
      
      
        =
      
      
        '
      
      
        number
      
      
        '
      
      
        ;

    field2:
      
      
        =
      
      
        '
      
      
        name
      
      
        '
      
      
        ;

    datatype2:
      
      
        =
      
      
        '
      
      
        varchar(20)
      
      
        '
      
      
        ;

    str_sql :
      
      
        =
      
      
        '
      
      
        create table 
      
      
        '
      
      
        ||
      
      tablename
      
        ||
      
      
        '
      
      
        (
      
      
        '
      
      
        ||
      
      field1 
      
        ||
      
      
        '
      
      
        '
      
      
        ||
      
      datatype1
      
        ||
      
      
        '
      
      
        ,
      
      
        '
      
      
        ||
      
      field2 
      
        ||
      
      
        '
      
      
        '
      
      
        ||
      
      datatype2
      
        ||
      
      
        '
      
      
        )
      
      
        '
      
      
        ;

    
      
      
        EXECUTE
      
      
         IMMEDIATE str_sql;

    EXCEPTION

        
      
      
        WHEN
      
       OTHERS 
      
        THEN
      
      
        

            DBMS_OUTPUT.put_line(
      
      
        '
      
      
        操作失败!
      
      
        '
      
      
        );


      
      
        END
      
      ;
    

 

  动态插入数据;  

      
        --
      
      
        动态处理费查询的DML语句:向刚才创建的表中插入数据
      
      
        DECLARE
      
      
        

  v_id 
      
      
        NUMBER
      
      ;                    
      
        --
      
      
        输入序号;
      
      

  v_name 
      
        VARCHAR
      
      (
      
        20
      
      );             
      
        --
      
      
        输入姓名;
      
      

  str_sql 
      
        VARCHAR2
      
      (
      
        500
      
      );          
      
        --
      
      
        保存拼接的SQL语句
      
      
        BEGIN
      
      
        

    v_id :
      
      
        =
      
      
        &
      
      
        vid;

    v_name :
      
      
        =
      
      
        '
      
      
        &name
      
      
        '
      
      
        ;

    str_sql :
      
      
        =
      
      
        '
      
      
        insert into t1 values(:1,:2)
      
      
        '
      
      ;      
      
        --
      
      
        使用占位符代表变量
      
      
        EXECUTE
      
      
         IMMEDIATE str_sql

    USING v_id,v_name;                              
      
      
        --
      
      
        使用变量替换SQL中的占位符,v_id替换:1,v_name替换:2,依此类推。
      
      
        COMMIT
      
      ;                                         
      
        --
      
      
        执行完毕后直接提交
      
      
        END
      
      ;
    

 

  查询表中的数据有多少行

      
        --
      
      
        处理单行查询的SELECT举例,查询表中的数据有多少行
      
      
        DECLARE
      
      
        

    v_count 
      
      
        NUMBER
      
      
        ;

    str_sql 
      
      
        VARCHAR2
      
      (
      
        500
      
      
        );


      
      
        BEGIN
      
      
        

    str_sql :
      
      
        =
      
      
        '
      
      
        select count(*) from t1
      
      
        '
      
      
        ;

    
      
      
        EXECUTE
      
       IMMEDIATE str_sql 
      
        INTO
      
       v_count;   
      
        --
      
      
        将查询的结果存放到变量v_count中。
      
      
            DBMS_OUTPUT.put_line(v_count);


      
      
        END
      
      ;
    

 

绑定变量的优缺点:

  1)可以再库缓存中共享游标,节省了CPU等资源,可以避免额外开销。

  2)SQL语句使用绑定变量可以避免被注入攻击。

  3)绑定变量是一种减少应用程序在分析查询时使用栓锁数目的可靠方法。

不适合使用变量绑定的情况:

  1)对于隔相当长一段时间才执行一次的SQL语句,利用绑定变量的好处hi被不能有效利用而抵消。

  2)在数据仓库的情况下。

  3)在对建有索引的字段,且字段非常大时,利用绑定变量可能会导致查询计划错误,从而导致查询效率非常低。

 

实现DDL语句中的注意事项:

  PL/SQL块使用动态SQL执行DDL语句的时候与其它不同,在DDL中不能使用绑定变量。

 

实现DML语句中的注意事项:

  不能使用绑定变量替换实际的数据库对象名(表,视图,列等),只能替换字面两,如果对象名在运行时生成的,我们只能使用字符串拼接。

 

 

2、通过游标实现多行查询的SELECT语句

  REF游标可以处理返回届国际的动态SQL。实现动态SQL的REF游标声明和普通REF游标相同,知识OPEN时绑定的是动态SQL字符串。

  例:查询emp表中所有的数据。

      
        DECLARE
      
      
        

  TYPE ref_cur 
      
      
        IS
      
       REF 
      
        CURSOR
      
      
        ;

    rc ref_cur;

    emprow emp
      
      
        %
      
      
        ROWTYPE;

    v_sql 
      
      
        VARCHAR2
      
      (
      
        100
      
      ):
      
        =
      
      
        '
      
      
        select * from emp where deptno = :x
      
      
        '
      
      ;   
      
        --
      
      
        动态执行的SQL语句
      
      
        BEGIN
      
      
        OPEN
      
       rc 
      
        FOR
      
       v_sql USING 
      
        30
      
      ;   
      
        --
      
      
        打开游标,绑定执行的SQL语句,并传递参数
      
      
          LOOP

        
      
      
        FETCH
      
       rc 
      
        INTO
      
      
         emprow;

        
      
      
        EXIT
      
      
        WHEN
      
       rc
      
        %
      
      
        NOTFOUND;

        dbms_output.put_line(
      
      
        '
      
      
        name:
      
      
        '
      
      
        ||
      
      emprow.ename
      
        ||
      
      
        '
      
      
          sal:
      
      
        '
      
      
        ||
      
      
        emprow.sal);

    
      
      
        END
      
      
         LOOP;

    
      
      
        CLOSE
      
      
         rc;


      
      
        END
      
      ;
    

 

3、DBMS_SQL程序包

  DBMS_SQL程序包是系统提供给我们的另一种使用动态SQL的方法。程序包中封装了一些列存储过程,帮助我们动态执行SQL。

  使用DBMS_SQL包实现动态SQL的步骤如下:

  1)将要执行的SQL语句或一个语句块放到一个字符串变量中。

  2)使用DBMS_SQL包的parse过程来分析该字符串。

  3)使用DBMS_SQL包的bind_variable过程来绑定变量。

  4)使用DBMS_SQL包的execute函数来执行语句。

  例:使用DBMS_SQL创建表  

      
        DECLARE
      
      
        

  tablename 
      
      
        VARCHAR2
      
      (
      
        20
      
      ) :
      
        =
      
      
        '
      
      
        t2
      
      
        '
      
      ;                 
      
        --
      
      
        表名
      
      

  field1 
      
        VARCHAR2
      
      (
      
        20
      
      ) :
      
        =
      
      
        '
      
      
        id
      
      
        '
      
      ;                    
      
        --
      
      
        字段1名称
      
      

  datatype1 
      
        VARCHAR2
      
      (
      
        20
      
      ) :
      
        =
      
      
        '
      
      
        number
      
      
        '
      
      ;             
      
        --
      
      
        字段1类型
      
      

  field2 
      
        VARCHAR2
      
      (
      
        20
      
      ) :
      
        =
      
      
        '
      
      
        name
      
      
        '
      
      ;                  
      
        --
      
      
        字段2名称
      
      

  datatype2 
      
        VARCHAR2
      
      (
      
        20
      
      ) :
      
        =
      
      
        '
      
      
        varchar(20)
      
      
        '
      
      ;        
      
        --
      
      
        字段2类型
      
      

  v_sql 
      
        VARCHAR2
      
      (
      
        500
      
      ) :
      
        =
      
      
        '
      
      
        create table 
      
      
        '
      
      
        ||
      
      tablename
      
        ||
      
      
        '
      
      
        (
      
      
        '
      
      
        ||
      
      field1 
      
        ||
      
      
        '
      
      
        '
      
      
        ||
      
      datatype1
      
        ||
      
      
        '
      
      
        ,
      
      
        '
      
      
        ||
      
      field2 
      
        ||
      
      
        '
      
      
        '
      
      
        ||
      
      datatype2
      
        ||
      
      
        '
      
      
        )
      
      
        '
      
      ;           
      
        --
      
      
        拼接SQL语句的字符串
      
      

  v_cursor 
      
        NUMBER
      
      ;                                
      
        --
      
      
        定义光标
      
      

  v_row 
      
        NUMBER
      
      ;                                   
      
        --
      
      
        行数
      
      
        BEGIN
      
      
        

    v_cursor:
      
      
        =
      
      dbms_sql.open_cursor;                              
      
        --
      
      
        为处理打开光标
      
      

    dbms_sql.parse(v_cursor,v_sql,dbms_sql.native);              
      
        --
      
      
        分析语句;
      
      

    v_row:
      
        =
      
      DBMS_SQL.
      
        execute
      
      (v_cursor);                           
      
        --
      
      
        执行sql语句;
      
      

    dbms_sql.close_cursor(v_cursor);                             
      
        --
      
      
        关闭光标;
      
      
            DBMS_OUTPUT.put_line(v_row);    


      
      
        END
      
      ;
    

  向表中插入一条数据:

      
        DECLARE
      
      
        

  v_id 
      
      
        NUMBER
      
       :
      
        =
      
      
        &
      
      
        vid;

    v_name 
      
      
        VARCHAR2
      
      (
      
        20
      
      ) :
      
        =
      
      
        '
      
      
        &vname
      
      
        '
      
      
        ;

    v_sql 
      
      
        VARCHAR2
      
      (
      
        100
      
      ) :
      
        =
      
      
        '
      
      
        insert into t2 values(:id,:name)
      
      
        '
      
      
        ;

    v_cursor 
      
      
        NUMBER
      
      
        ;

    v_row 
      
      
        NUMBER
      
      
        ;


      
      
        BEGIN
      
      
        

    v_cursor:
      
      
        =
      
      
        dbms_sql.open_cursor;

    dbms_sql.parse(v_cursor,v_sql,dbms_sql.native);

    dbms_sql.bind_variable(v_cursor,
      
      
        '
      
      
        :id
      
      
        '
      
      
        ,v_id);

    dbms_sql.bind_variable(v_cursor,
      
      
        '
      
      
        :name
      
      
        '
      
      
        ,v_name);

    v_row :
      
      
        =
      
       dbms_sql.
      
        execute
      
      
        (v_cursor);

    dbms_sql.close_cursor(v_cursor);

    
      
      
        COMMIT
      
      
        ;

    DBMS_OUTPUT.put_line(v_row);


      
      
        END
      
      ;
    

 

  查询EMP中的数据

      
        DECLARE
      
      
        

  V_DEPTNO 
      
      
        NUMBER
      
       :
      
        =
      
      
        &
      
      
        DEPTNO;

  V_SQL    
      
      
        VARCHAR2
      
      (
      
        100
      
      ) :
      
        =
      
      
        '
      
      
        select empno,ename,sal from emp where deptno = :deptno
      
      
        '
      
      
        ;

  V_CURSOR 
      
      
        NUMBER
      
      
        ;

  V_NO     
      
      
        NUMBER
      
      
        ;

  V_ENAME  
      
      
        VARCHAR2
      
      (
      
        20
      
      
        );

  V_SAL    
      
      
        NUMBER
      
      
        ;

    v_start  
      
      
        NUMBER
      
      
        ;


      
      
        BEGIN
      
      
        

  V_CURSOR :
      
      
        =
      
       DBMS_SQL.OPEN_CURSOR;                                  
      
        --
      
      
        打开游标
      
      

  DBMS_SQL.PARSE(V_CURSOR, V_SQL, DBMS_SQL.NATIVE);                  
      
        --
      
      
        解析动态SQL语句
      
      

  DBMS_SQL.BIND_VARIABLE(V_CURSOR, 
      
        '
      
      
        :deptno
      
      
        '
      
      , V_DEPTNO);             
      
        --
      
      
        传递参数
      
      
        

  DBMS_SQL.DEFINE_COLUMN(V_CURSOR, 
      
      
        1
      
      , V_NO);                         
      
        --
      
      
        定义输出的列,和查询的列相匹配
      
      

  DBMS_SQL.DEFINE_COLUMN(V_CURSOR, 
      
        2
      
      , V_ENAME,
      
        20
      
      
        );

  DBMS_SQL.DEFINE_COLUMN(V_CURSOR, 
      
      
        3
      
      
        , V_SAL);



  v_start :
      
      
        =
      
       DBMS_SQL.
      
        execute
      
      (V_CURSOR);                             
      
        --
      
      
        执行SQL语句,需要有接受返回值
      
      
        

  LOOP

    
      
      
        EXIT
      
      
        WHEN
      
       DBMS_SQL.FETCH_ROWS(V_CURSOR) 
      
        <=
      
      
        0
      
      ;                    
      
        --
      
      
        解析游标,
      
      

    DBMS_SQL.COLUMN_VALUE(V_CURSOR, 
      
        1
      
      , V_NO);                         
      
        --
      
      
        将当前行的数据写入上面对应的列中。
      
      

    DBMS_SQL.COLUMN_VALUE(V_CURSOR, 
      
        2
      
      
        , V_ENAME);

    DBMS_SQL.COLUMN_VALUE(V_CURSOR, 
      
      
        1
      
      
        , V_SAL);

  

    DBMS_OUTPUT.PUT_LINE(
      
      
        '
      
      
        no:
      
      
        '
      
      
        ||
      
       V_NO 
      
        ||
      
      
        '
      
      
          enmae:
      
      
        '
      
      
        ||
      
       V_ENAME 
      
        ||
      
      
        '
      
      
            sal:
      
      
        '
      
      
        ||
      
       V_SAL);   
      
        --
      
      
        输出内容
      
      
        END
      
      
         LOOP;

  dbms_sql.close_cursor(v_cursor);                                     
      
      
        --
      
      
        关闭游标
      
      
        END
      
      ;
    

 

Oracle基础 动态SQL语句


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论