Oracle基础 动态SQL语句

本文详细介绍了静态SQL和动态SQL的概念与应用场景,包括如何使用EXECUTE IMMEDIATE语句、游标和DBMS_SQL程序包来实现动态创建DML、DDL语句。同时探讨了绑定变量的优缺点及其适用场景。
摘要由CSDN通过智能技术生成

一、静态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;

 

转载于:https://www.cnblogs.com/zhengcheng/p/4207376.html

动态sql语句基本语法 1 :普通SQL语句可以用Exec执行 例: Select * from tableName Exec('select * from tableName') Exec sp_executesql N'select * from tableName' -- 请注意字符串前一定要加N 2:字段名,表名,数据库名之类作为变量时,必须用动态SQL 错误: declare @fname varchar(20) set @fname = 'FiledName' Select @fname from tableName -- 错误,不会提示错误,但结果为固定FiledName,并非所要。 正确: Exec('select ' + @fname + ' from tableName') -- 请注意加号前后的单引号的边上加空格 当然将字符串改成变量的形式也可 declare @fname varchar(20) set @fname = 'FiledName' --设置字段名 declare @s varchar(1000) set @s = 'select ' + @fname + ' from tableName' Exec(@s) -- 成功 exec sp_executesql @s -- 此句会报错 --注:@s参数必须为ntext或nchar或nvarchar类型,必须将declare @s varchar(1000) 改为declare @s Nvarchar(1000) 如下: declare @s Nvarchar(1000) -- 注意此处改为nvarchar(1000) set @fname = 'FiledName' --设置字段名 set @s = 'select ' + @fname + ' from tableName' Exec(@s) -- 成功 exec sp_executesql @s -- 此句正确 3. 输入或输出参数 (1)输入参数: declare @QueryString nvarchar(1000) --动态查询语句变量(注:必须为ntext或nchar哐nvarchar类型,不能是varchar类型) declare @paramstring nvarchar(200) --设置动态语句中的参数的字符串(注:必须为ntext或nchar哐nvarchar类型,不能是varchar类型) declare @input_id int--定义需传入动态语句的参数的 set @QueryString='select * from tablename where id=@id' --id为字段名,@id为要传入的参数 set @paramstring='@id int' --设置动态语句中参数的定义的字符串 set @input_id =1 --设置需传入动态语句的参数的为1 exec sp_executesql @querystring,@paramstring,@id=@input_id   若有多个参数: declare @QueryString nvarchar(1000) --动态查询语句变量(注:必须为ntext或nchar哐nvarchar类型,不能是varchar类型) declare @paramstring nvarchar(200) --设置动态语句中的参数的字符串(注:必须为ntext或nchar哐nvarchar类型,不能是varchar类型) declare @input_id int--定义需传入动态语句的参数的,参数1 declare @input_name varchar(20)--定义需传入动态语句的参数的,参数2 set @QueryString='select * from tablename where id=@id and name=@name' --id与name为字段名,@id与@name为要传入的参数 set @paramstring='@id int,@name varchar(20)' --设置动态语句中参数的定义的字符串,多个参数用","隔开 set @input_id =1 --设置需传入动态语句的参数的为1 set @input_name='张三' --设置需传入动态语句的参数的为"张三" exec sp_executesql @querystring,@paramstring,@id=@input_id,@name=@input_name --请注意参数的顺序 (2)输出参数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值