动态SQL

来源:互联网 发布:知乎客户端复制 编辑:程序博客网 时间:2024/04/28 01:57

动态SQL简介:
   1、静态SQL
      静态SQL是指直接嵌入在PL/SQL块中的SQL语句。在编写PL/SQL时。静态SQL用于完成特定或固定的任务:
   2、动态SQL
      动态SQL是指在运行PL/SQL块时动态输入的SQL语句。如果在PL/SQL中需要执行DDL语句,DCL语句(GRANT,REVOKE),或者在PL/SQL中需要执行更加灵活的SQL语句(例如在SELECT语句中使用不同的WHERE条件),那么就必须使用动态SQL。
      在PL/SQL块中编写动态语句时,需要将SQL语句存放在字符创变量中,而且SQL语句可以包含占位符(以冒号开始)。
       如:CREATE TABLE temp(cola INT,colb VARCHAR2(10))
           GRANT SELECT ON temp TO smith
           DELETE FROM emp WHERE sal>:a
           SELECT ename,sal FROM emp WHERE empno=:l
   3、动态SQL的处理方法
      (1)、使用EXECUTE IMMEDIATE
             不能用于处理多行查询语句。
      (2)、使用OPEN-FOR FETCH 和CLOSE语句
             为了处理动态的多行查询操作,必须使用OPEN-FOR语句打开游标,使用FETCH 语句提取循环数据,最终使用CLOSE语句关闭游标.
      (3)、使用批量动态SQL

处理非查询语句
   为了动态的处理非查询语句(DML DDL DCL)或者单行查询语句,可以在PL/SQL快中使用EXEXUTE IMMEDIATE 语句,                                
     EXECUTE IMMEDIATE dynamic_string
     [INTO |define_variable|,define_variable...|record]
     [USING [IN|OUT|INOUT] bind_argument...]
     [{RETURNING|RETURN} INTO bind_argument...];
   dynamic_string 用于指定存放SQL语句或者PL/SQL块的字符串变量;
   define_variable用于指定存放单行查询结婚的变量
   输入bind_argument(IN)用于指定存放被传递给动态SQL值的变量
   输出bind_argument(OUT)用于指定存放动态SQL返回值的变量
   1、使用EXECUTE IMMEDIATE 处理DDL操作
      EXECUTE IMMEDIATE后面只需要带有DDL语句文本即可,而不需要INTO和USING 
  字句。
      CREATE OR REPLACE PROCEDURE drop_table(table_name VARCHAR2)
      IS
        sql_statement VARCHAR2(100);
      BEGIN
        sql_statement:='DROP TABLE '||table_name;
        EXECUTE IMMEDIATE sql_statement;
      END; 
    2、使用EXECUTE IMMEDIATE 处理DCL操作
        和处理DDL语句差不多
    3、使用EXECUTE IMMEDIATE 处理DML 语句
       如果DML语句既没有占位符,也咩有RETURNING 字句,那么在EXECUTE IMMEDIATE 语句之后不需要带有USING和RETURNING INTO子句;
       如果DML语句含有占位符,那么在   EXECUTE IMMEDIATE 语句之后要带有USING子句;
       如果DML语句之后带有RETURNING子句,那么在EXECUTE IMMEDIATE 语句之后带有RETURNING INTO子句。
      (1)、处理无占位符和RETURNING子句的DML语句
         DECLARE
          sql_statement VARCHAR2(100);
         BEGIN
          sql_statement:='UPDATE emp SET sal=sal*1.1 WHERE depno=30';
          EXECUTE IMMEDIATE sql_statement;
         END;
       (2)、处理包含占位符的DML语句
          要使用USING 自己为占位符提供输入数据。
          DECLARE
             sql_state VARCHAR2(100);
          BEGIN
             sql_state:='UPDATE emp SET sal=sal*(1+:percent/100) WHRE deptno=:dno';
             EXECUTE IMMEDIATE sql_state USING &1,&2;
          END;
       (3)、处理包含RETURNING 子句的DML语句
          必要要使用RETURNING INTO 子句接受返回数据。
          注意:直接使用EXECUTE IMMEDIATE 语句处理带有RETURNING 子句的DML语句时,只能处理作用在单行的DML语句。
               如果DML语句作用在多行伤,则必须要使用BULK子句。
          DECLARE
             salary NUMBER(6,2);
             sql_state VARCHAR2(100);
          BEGIN
             sql_state:='UPDATE emp SET sal=(sal*:present/100) WHERE empno=:eno RETURNING sal INTO :salary';
             EXECUTE IMMEDIATE sql_state USING &1,&2 RETURNING INTO salary;
             dbms_output.put_line('新工资:'||salary);
          END; 
       (4)、使用EXECUTE IMMEDIATE 处理单行查询
          要使用INTO 子句接受返回数据
          DECLARE
            sql_state VARCHAR2(100);
            emp_record emp%ROWTYPE;
          BEGIN
             sql_state:='SELECT * FROM emp WHERE empno=:eno';
             EXECUTE IMMEDIATE  sql_state INTO emp_record USING &1;   
             dbms_output.put_line('雇员:'||emp_record.ename||'的工资为:'||emp_record.sal); 
          END;
处理多行查询语句:
  使用EXECUTE IMMEDIATE只能处理单行查询语句,为了动态的处理SELECT语句所返回的多行数据,需要使用OPEN-FOR,FETCH,CLOSE语句。
  步骤如下
    定义游标变量-->打开游标变量-->循环提取数据-->关闭游标变量。
    1、定义游标变量:
       TYPE cursortype IS REF CURSOR;
       cursor_variable cursortype;
    2、打来游标变量
       OPEN   cursor_variable FOR dynamic_string [USING bind_argument,...];
        bind_argument 用于存放传递给动态SELECT语句值的变量。
    3、循环提取数据
       FETCH cursor_variable INTO {var1[,var2]...|record_var};
    4、关闭游标变量
       close cursor_variable;
    5、多行查询实例:
        DECLARE
          TYPE cursor_type IS REF CURSOR;
          sql_state VARCHAR2(100);
          emp_record emp%ROWTYPE;
          v_cursor vursor_type;
        BEGIN
          sql_state:='SELECT * FROM emp WHERE deptno=:dno';
          OPEN  v_cursor FOR sql_state USING &deptno;
          LOOP
            FETCH   v_cursor INTO emp_record;
            EXIT WHEN v_cursor%NOTFOUND;
            dbms_output.put_line('雇员名:'||emp_record.ename||'的工资是:'||emp_record.salary);
          END LOOP;
          CLOSE v_cursor;
        END;
在动态SQL中使用BULK子句
  ORACLE9i新增加的特性。可以加快批量数据的处理速度。
  有三种语句支持BULK子句:EXECUTE IMMEDIATE,FETCH和FORALL
  1、在EXECUTE IMMEDIATE语句中使用动态BULK子句
       EXECUTE IMMEDIATE dynamic_string
     [BULK COLLECT INTO |define_variable|,define_variable...|record]
     [USING [IN|OUT|INOUT] bind_argument...]
     [{RETURNING|RETURN} BULK COLLECT INTO bind_argument...]; 
   (1)、使用BULK子句处理DML语句返回子句
        DECLARE
          TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
          TYPE sal_table_type IS TABLE OF emp.sal%TYPE INDEX BY BINARY_INTEGER;
          ename_table ename_table_type;
          sal_table sal_table_type;
          sql_state VARCHAR2(150);
        BEGIN
          sql_state:='UPDATE emp SET sal=sal*(1+:precent/100) WHERE deptno=:dno'
             ||'RETURNING ename,sal INTO :name,:salary';
          EXECUTE IMMEDIATE sql_state USING &precent,&depno RETURNING BULK COLLECT INTO
           ename_table,sal_table   ;
           FOR i IN 1..ename_table.COUNT LOOP
              dbms_output.put_line('雇员名:'||ename_table(i)||'的工资是:'||sal_table(i));
           END LOOP;
         END;                                   
       (2)、使用BULK子句处理多行查询                              
          DECLARE
            sql_state VARCHAR2(100);
            TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
            ename_table ename_table_type;
          BEGIN
             sql_state:='SELECT ename FROM emp WHERE empno=:eno';
             EXECUTE IMMEDIATE  sql_state BULK COLLECT INTO emp_record USING &1;
             FOR i IN 1..ename_table.COUNT LOOP  
               dbms_output.put_line('雇员:'||ename_table(i)); 
             END LOOP; 
          END;
  2、在FETCH 语句中使用BULK子句
     OPEN-FOR ,FETCH,CLOSE .....BULK
     DECLARE
        TYPE cursor_type IS REF CURSOR;
        TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
        sql_state VARCHAR2(200);
        v_vursor cursor_type;
        ename_table ename_table_type;
     BEGIN
        sql_state:='SELECT ename FROM emp WHERE deptno=:dno';
        OPEN v_corsor FOR sql_state USING &deptno;
        FETCH v_cursor BULK COLLECT INTO ename_table;
        FOR i IN i..ename_table.COUNT LOOP
             dbms_output.put_line('雇员:'||ename_table(i)); 
        END LOOP;
        CLOSE   v_cursor;
     END; 
  FORALL       

原创粉丝点击