欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

Oracle 绑定变量(bind variable) 有大用 有大大用

【动态SQL定义】

动态SQL是指在PL/SQL块中,可以根据不同参数拼接不同的SQL字符串,即执行前不能确定该SQL是什么(如表名、字段名或条件值未知)。

【动态SQL与静态SQL区别】

1)静态SQL是确定的,在执行前已经完成编译(随PL/SQL块一起完成了编译),执行时数据库直接执行编译好的SQL;而动态SQL是不确定的,是在程序运行时才编译并执行(不随PL/SQL块编译时编译)。

2)静态SQL一次编译,多次调用,使用相同的执行计划。动态SQL每次运行均要先对其编译,即多次调用则需要多次编译。

3)静态SQL使用相同的执行计划,对于确定的任务而言,静态SQL更具有高效性,但缺乏灵活性;动态SQL使用了不同的执行计划,效率不如静态SQL,但能够解决复杂的问题。

4)动态SQL容易产生SQL注入,为数据库安全带来隐患。

【动态SQL用途】

1)处理PL/SQL块中不能处理的DDL或DCL语句;

2)处理PL/SQL块中带参数具有不确定性的SQL(如表名、字段名或条件值作为变量);

3)PL/SQL中静态SQL出现性能瓶颈;

【动态SQL语法】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
execute immediate 'sql';

--区别于静态SQL变量赋值的INTO位置,select col into var from table;

execute immediate 'sql_select' into var_1, var_2;

execute immediate 'sql' using bind_var_1,bind_var_2;

execute immediate 'sql_select' into var_1, var_2 using bind_var_1,bind_var_2;

-- returning子句在insert之后返回新加的值,update之后返回修改后的值,delete返回删除前的值

execute immediate 'sql_dml' returning into var_1;

--批量动态SQL,即在动态SQL中使用BULK子句,或使用游标变量时在fetch中使用BULK,或在FORALL语句中使用BULK子句来实现

execute immediate 'sql' bulk collect into var_array;

--动态REF游标,不同于静态游标声明方式

open cursor_name for ‘sql’ using bind_var_1;

【动态SQL举例】

1
2
3
4
5
6
7
8
9
/*动态SQL执行DDL语句(不能跟using)*/
declare
 sql_statement varchar2(100);
 table_name    varchar2(20);
begin
 table_name := 'emp';
 sql_statement := 'truncate table ' || table_name;
 execute immediate sql_statement;
end;

–注:变量不能放在引号内,否则会解析成文本而不是变量,但若在DML语句的绑定变量,则需要在引号内,拼SQL时一定要注意关键字后的空格,如truncate table之后是有一个空格的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*动态SELECT语句(不能跟returning)*/
/*SELECT中表名是变量*/
declare
 sql_stat varchar2(100);
 v_tab    varchar2(20);
begin
 v_tab := 'emp';
 sql_stat := 'select sal from '|| v_tab || ' where empno = 1';
 dbms_output.put_line(sql_stat);
 execute immediate sql_stat;
end;
--注:注意from后面和where前面是有空格的
/*SELECT INTO变量赋值*/
declare
 sql_stat varchar2(100);
 v_sal    number(6, 2);
begin
 sql_stat := 'select sal from emp where empno = :1';
 execute immediate sql_stat
   into v_sal
   using 1;
 dbms_output.put_line(v_sal);
end;

–注:INTO的位置,不像静态SQL一样在字段名后,而是在execute immediate时才加,且关键字在using之前;另外,注意区分有returning子句的,returning子句在SQL文本和execute immediate子句中均有出现,但此时INTO的位置在using之后。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*动态SQL执行DML语句(含returning子句)*/
declare
 v_sal    number(6, 2);
 sql_stat varchar2(100);
 v_eno    number(2);
begin
 v_eno    := 1;
 sql_stat := 'update emp set sal = sal * (1 + :percent / 100) where empno = :2 returning sal into :3';
 execute immediate sql_stat
   using &1, v_eno
   returning into v_sal;
 commit;
 dbms_output.put_line('new salary: ' || v_sal);
end;

–注:动态SQL内的结尾不加分号“;”,但PL/SQL的语句结尾加“;”,且冒号后的占位符是字母或数字完全没有影响,using的变量值可以是绑定变量、或变量或常量均可。如:占位符:percent对应绑定变量&1,虽然名字完全不同,但也不影响,另外,占位符:2对应了变量v_eno,也是完全不同。即,按顺序占位,与占位符名无关。按顺序绑定变量,与绑定变量名无关。给占位符或绑定变量命名只是为了程序的可读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
declare
 type cur_totalvaue_type is ref cursor;
 cur_totalvaue     cur_totalvaue_type;
 sql_stat          VARCHAR2(100);
 record_totalvalue t_threeyear_hour%rowtype;
begin
 sql_stat := 'select * from t_threeyear_hour t where t.time = :1';
 open cur_totalvaue for sql_stat
   using to_date('20130209', 'yyyymmdd');
 loop
   fetch cur_totalvaue
     into record_totalvalue;
   exit when cur_totalvaue%NOTFOUND;
   dbms_output.put_line(record_totalvalue.time || ' is ' || record_totalvalue.totalvalue);
 end loop;
 close cur_totalvaue;
end;
/*批量动态SQL(BULK COLLECT INTO )*/
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_stat    varchar2(120);
 v_percent   number := &percent;
 v_dno       number := &dno;
begin
 sql_stat := 'update emp set sal = sal * (1 + :percent / 100)' ||
             ' where deptno = :dno' ||
             ' returning ename, sal into :name, :salary';
 execute immediate sql_stat
   using v_percent, v_dno
   returning bulk collect
   into ename_table, sal_table;
 for i in 1 .. ename_table.count loop
   dbms_output.put_line('employee ' || ename_table(i) || ' salary is: ' || sal_table(i));
 end loop;
end;
/*动态游标+BULK*/
declare
 type cur_emp_type is ref cursor;
 cur_emp cur_emp_type;
 type ename_table_type is table of emp.ename%type index by binary_integer;
 ename_table ename_table_type;
 sql_stat    varchar2(120);
begin
 sql_stat := 'select ename from emp where deptno = :dno';
 open cur_emp for sql_stat
   using &dno;
 fetch cur_emp bulk collect
   into ename_table;
 for i in 1 .. ename_table.count loop
   dbms_output.put_line('employee name is ' || ename_table(i));
 end loop;
 close cur_emp;
end;
/*FORALL+BULK(仅支持DML)*/
declare
 type ename_table_type is table of tb2.ename%type;
 type sal_table_type is table of tb2.sal%type;
 ename_table ename_table_type;
 sal_table   sal_table_type;
 sql_stat    varchar2(100);
begin
 ename_table := ename_table_type('blake', 'ford', 'miller'); --为复合类型赋值
 sql_stat    := 'update tb2 set sal = sal * 1.1 where ename = :1 returning sal into :2';
 forall i in 1 .. ename_table.count
 execute immediate sql_stat using ename_table(i)
 returning bulk collect into sal_table;
 for j in 1 .. ename_table.count loop
   dbms_output.put_line('the new salary is ' || sal_table(j) || ' for ' || ename_table(j));
 end loop;
end;

【绑定变量】

Oracle会自动把循环中带参数SQL语句转换为采用绑定变量方式执行,以减少硬解析和latch竞争。所以,很多时候我们并不需要专门去注意在PL/SQL块中使用绑定变量,Oracle会自动帮我们完成这个动作。至于SQLPLUS中使用绑定变量,其实我们日常也较少使用SQLPLUSE,故也无需专门注意该问题。

1
2
3
4
5
6
7
-- sqlplus中使用绑定变量

variable x number(4);

exec :x := 1;

select * from emp t where empno = :x;

–注:必须先使用关键字variable声明变量,再使用exec给绑定变量赋值(变量前带冒号),最后使用绑定变量。

绑定变量效率高的原因

Oracle中,对于一个提交的sql语句,存在两种可选的解析过程,一种叫做硬解析,一种叫做软解析。当一个sql语句提交后,oracle会首先检查一下共享缓冲池(shared pool)里有没有与之完全相同的语句,如果有的话只须执行软分析即可,否则就得进行硬分析。

硬解析需要经解析,制定执行路径、优化访问计划等许多的步骤。硬解释不仅仅耗费大量的cpu,更重要的是会占据重要闩(latch)资源,严重的影响系统规模扩大(即限制了系统的并发行),而且引起的问题不能通过增加内存条和cpu的数量来解决。之所以这样是因为闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改。

若Oracle在shared pool中查找相同SQL语句的过程中,SQL语句使用了绑定变量(bind variable),那么就是比较SQL语句的静态部分,前面我们已经知道,静态部分是有限的,很容易就能够缓存在内存里,从而找到相同的SQL语句的概率很高。如果没有使用绑定变量,则就是比较SQL语句的静态部分和动态部分,而动态部分的变化是无限的,因此这样的SQL语句很难被缓存在shared pool里。毕竟内存是有限的,不可能把所有的动态部分都缓存在sharedpool里,即便能够缓存,管理这样一个无限大的shared pool也是不可能完成的任务。不使用绑定变量导致的直接结果就是,找到相同的SQL语句的概率很低,导致必须完整的解析SQL语句,也就导致消耗更多的资源。

绑定变量的使用环境

由于在OLTP中,SQL语句大多是比较简单或者操作的结果集都很小。当一个表上创建了索引,那么这种极小结果集的操作使用索引最合适,并且几乎所有的SQL的执行计划的索引都会被选择,因为这种情况下,索引可能只需要扫描几个数据块就可以定位到数据,而全表扫描将会相当耗资源。因此,这种情况下,即使每个用户的谓词条件不一样,执行计划也是一样的,就是都用索引来访问数据,基本不会出现全表扫描的情况。在这种执行计划几乎唯一的情况下,使用绑定变量来代替谓词常量是合适的。

注意,在OLTP中使用绑定变量一定要注意,变量的类型要与表字段类型一样,否则若造成了隐式转换,索引将失效而采用全表扫描,此时会造成系统性能的极大下降。

在OLAP系统中,SQL的操作就复杂很多,OLAP数据库上大多数时候运行的一些报表SQL,这些SQL经常会用到聚合查询(如:groupby),而且结果集也是非常庞大,在这种情况下,索引并不是必然的选择,甚至有时候全表扫描的性能会更优于索引,即使相同的SQL,如果谓词不同,执行计划都可能不同。让Oracle对每条SQL做硬分析,确切的知道谓词条件的值,这对执行计划的选择至关重要,这样做的原因是为了得到一个最优的执行计划。在OLAP系统中,系统的资源基本上是用于做大的SQL查询,和查询比起来SQL解析消耗的资源显得微不足道,SQL硬分析的代价是可以忽略的。因此让Oracle确切地知道谓词的数值至关重要,它直接决定了SQL执行计划的选择,所以在OLAP系统完全没有必要绑定变量,那样很可能带来负面影响,比如导致SQL选择错误的执行,这个代价有时是灾难性的。

【文章参考】

http://blog.csdn.net/leshami/article/details/6118010

http://czmmiao.iteye.com/blog/1489625


来自 https://betgar.github.io/2018/04/16/oracle-bind-variable/



ORACLE 绑定变量用法总结

之前对ORACLE中的变量一直没个太清楚的认识,比如说使用:、&、&&、DEIFINE、VARIABLE……等等。今天正好闲下来,上网搜了搜相关的文章,汇总了一下,贴在这里,方便学习。

==================================================================================


 oracle 中,对于一个提交的sql语句,存在两种可选的解析过程一种叫做硬解析,一种叫做软解析.

一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解释不仅仅耗费大量的cpu,更重要的是会占据重要的们闩(latch)资源,严重的影响系统的规模的扩大(即限制了系统的并发行),而且引起的问题不能通过增加内存条和cpu的数量来解决。之所以这样是因为门闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改。当一个sql语句提交后,oracle会首先检查一下共享缓冲池(shared pool)里有没有与之完全相同的语句,如果有的话只须执行软分析即可,否则就得进行硬分析。

 而唯一使得oracle 能够重复利用执行计划的方法就是采用绑定变量。绑定变量的实质就是用于替代sql语句中的常量的替代变量。绑定变量能够使得每次提交的sql语句都完全一样。

 

1.


sqlplus中如何使用绑定变量,可以通过variable来定义

[c-sharp] view plaincopy

  1. SQL> select * from tt where id=1;  

  2.   

  3. ID NAME  

  4. ---------- ----------------------------------------  

  5. 1 test  

  6.   

  7. SQL> select * from tt where id=2;  

  8.   

  9. ID NAME  

  10. ---------- ----------------------------------------  

  11. 2 test  

  12.   

  13. SQL> variable i number;  

  14. SQL> exec :i :=1;  

  15.   

  16. PL/SQL 过程已成功完成。  

  17.   

  18. SQL> select *from tt where id=:i;  

  19.   

  20. ID NAME  

  21. ---------- ----------------------------------------  

  22. 1 test  

  23.   

  24. SQL> exec :i :=2;  

  25.   

  26. PL/SQL 过程已成功完成。  

  27.   

  28. SQL> select *from tt where id=:i;  

  29.   

  30. ID NAME  

  31. ---------- ----------------------------------------  

  32. 2 test  

  33.   

  34. SQL> print i;  

  35.   

  36. I  

  37. ----------  

  38. 2  

  39.   

  40. SQL> select sql_text,parse_calls from v$sql where sql_text like 'select * from t  

  41. t where id=%';  

  42.   

  43. SQL_TEXT PARSE_CALLS  

  44. ------------------------------------------------------------ -----------  

  45. select * from tt where id=2 1  

  46. select * from tt where id=1 1  

  47. select * from tt where id=:i 2  

  48. SQL>  


从上面试验发现绑定变量i的使用使查询id=1id=2sqlselect *from tt where id=:i得以重复
使用,从而避免了hard parse,这里的PARSE_CALLS2包括了一次soft parse





2.

前两天看到有人在pub上问sqlplus中通过definevariable定义的变量的区别。其实define定义的我

理解不是变量而是字符常量,通过define定义之后,在通过&或者&&引用的时候不需要输入了,仅此而已。

oracle在执行的时候自动用值进行了替换;而variable定义的是绑定变量,上面已经提到。

[c-sharp] view plaincopy

  1. C:>sqlplus xys/manager  

  2. SQL*Plus: Release 11.1.0.6.0 - Production on 星期二 4月 1 14:03:00 2008  

  3. Copyright (c) 1982, 2007, Oracle. All rights reserved.  

  4.   

  5. 连接到:  

  6. Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production  

  7. With the Partitioning, OLAP, Data Mining and Real Application Testing options  

  8. SQL> define  

  9. DEFINE _DATE = "01-4月 -08" (CHAR)  

  10. DEFINE _CONNECT_IDENTIFIER = "db11" (CHAR)  

  11. DEFINE _USER = "XYS" (CHAR)  

  12. DEFINE _PRIVILEGE = "" (CHAR)  

  13. DEFINE _SQLPLUS_RELEASE = "1101000600" (CHAR)  

  14. DEFINE _EDITOR = "Notepad" (CHAR)  

  15. DEFINE _O_VERSION = "Oracle Database 11g Enterprise Edition Release 11.1.0.  

  16. 6.0 - Production  

  17. With the Partitioning, OLAP, Data Mining and Real Application Testing options" (  

  18. CHAR)  

  19. DEFINE _O_RELEASE = "1101000600" (CHAR)  

  20. SQL> select *from tt;  

  21. ID NAME  

  22. ---------- ----------  

  23. 1 a  

  24. 2 a  

  25. "abc"  

  26. SQL> define a  

  27. SP2-0135: 符号 a 未定义  

  28. SQL> define a=1  

  29. SQL> define  

  30. DEFINE _DATE = "01-4月 -08" (CHAR)  

  31. DEFINE _CONNECT_IDENTIFIER = "db11" (CHAR)  

  32. DEFINE _USER = "XYS" (CHAR)  

  33. DEFINE _PRIVILEGE = "" (CHAR)  

  34. DEFINE _SQLPLUS_RELEASE = "1101000600" (CHAR)  

  35. DEFINE _EDITOR = "Notepad" (CHAR)  

  36. DEFINE _O_VERSION = "Oracle Database 11g Enterprise Edition Release 11.1.0.  

  37. 6.0 - Production  

  38. With the Partitioning, OLAP, Data Mining and Real Application Testing options" (CHAR)  

  39. DEFINE _O_RELEASE = "1101000600" (CHAR)  

  40. DEFINE A = "1" (CHAR)  

  41. --通过上面显示define定义的应该是字符(串)常量。  

  42. SQL> select * from tt where id=&a;  

  43. 原值 1: select * from tt where id=&a  

  44. 新值 1: select * from tt where id=1  

  45. ID NAME  

  46. ---------- ----------  

  47. 1 a  

  48. SQL> select * from tt where id=&&a;  

  49. 原值 1: select * from tt where id=&&a  

  50. 新值 1: select * from tt where id=1  

  51. ID NAME  

  52. ---------- ----------  

  53. 1 a  

  54. SQL> define b='a';  

  55. SQL> define  

  56. DEFINE _DATE = "01-4月 -08" (CHAR)  

  57. DEFINE _CONNECT_IDENTIFIER = "db11" (CHAR)  

  58. DEFINE _USER = "XYS" (CHAR)  

  59. DEFINE _PRIVILEGE = "" (CHAR)  

  60. DEFINE _SQLPLUS_RELEASE = "1101000600" (CHAR)  

  61. DEFINE _EDITOR = "Notepad" (CHAR)  

  62. DEFINE _O_VERSION = "Oracle Database 11g Enterprise Edition Release 11.1.0.  

  63. 6.0 - Production  

  64. With the Partitioning, OLAP, Data Mining and Real Application Testing options" (  

  65. CHAR)  

  66. DEFINE _O_RELEASE = "1101000600" (CHAR)  

  67. DEFINE A = "1" (CHAR)  

  68. DEFINE B = "a" (CHAR)  

  69.   

  70. --如果是字符类型那么在引用时别忘了加上单引号,另外通过define定义之后在引用时不需要输入了。  

  71. SQL> select * from tt where name=&&b;  

  72. 原值 1: select * from tt where name=&&b  

  73. 新值 1: select * from tt where name=a  

  74. select * from tt where name=a  

  75. *  

  76. 第 1 行出现错误:  

  77. ORA-00904: "A": 标识符无效  

  78.   

  79. SQL> select * from tt where name='&&b';  

  80. 原值 1: select * from tt where name='&&b'  

  81. 新值 1: select * from tt where name='a'  

  82. ID NAME  

  83. ---------- ----------  

  84. 1 a  

  85. 2 a  

  86. SQL> select * from tt where name='&b';  

  87. 原值 1: select * from tt where name='&b'  

  88. 新值 1: select * from tt where name='a'  

  89. ID NAME  

  90. ---------- ----------  

  91. 1 a  

  92. 2 a  

  93. --执行sql时进行了替换  

  94. SQL> select sql_text from v$sql where sql_text like 'select * from tt where name  

  95. =%';  

  96. SQL_TEXT  

  97. --------------------------------------------------------------------------------  

  98. select * from tt where name=1  

  99. select * from tt where name='a'  

  100. SQL>  




3.

oracle在解析sql时会把plsql中定义的变量转为为绑定变量

[c-sharp] view plaincopy

  1. SQL> create table tt(id int , name varchar2(10));  

  2.   

  3. 表已创建。  

  4.   

  5. SQL> alter session set sql_trace=true;  

  6.   

  7. 会话已更改。  

  8.   

  9. SQL> declare  

  10. 2 begin  

  11. for i in 1..100 loop  

  12. 4 insert into tt values(i,'test');  

  13. 5 end loop;  

  14. 6 commit;  

  15. 7 end;  

  16. 8 /  

  17.   

  18. PL/SQL 过程已成功完成。  

  19.   

  20. SQL> alter session set sql_trace=false;  

  21. --trace file:  

  22. =====================  

  23. PARSING IN CURSOR #3 len=90 dep=0 uid=31 oct=47 lid=31 tim=7109565004 hv=962259239   

  24.   

  25. ad='668ec528'  

  26. declare  

  27. begin  

  28. for i in 1..100 loop  

  29. insert into tt values(i,'test');  

  30. end loop;  

  31. commit;  

  32. end;  

  33. END OF STMT  

  34. PARSE #3:c=15625,e=5678,p=0,cr=3,cu=0,mis=1,r=0,dep=0,og=1,tim=7109564996  

  35. =====================  

  36. PARSING IN CURSOR #5 len=34 dep=1 uid=31 oct=2 lid=31 tim=7109565520 hv=1299226876   

  37.   

  38. ad='66869934'  

  39. INSERT INTO TT VALUES(:B1 ,'test')  

  40. END OF STMT  

  41. PARSE #5:c=0,e=226,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,tim=7109565513  

  42. =====================  


另外从hard parse的数据量上其实也可以大致猜测oracle会把plsql中定义的变量转换为绑定变量处理
[c-sharp] view plaincopy

  1. SQL> connect /as sysdba  

  2. 已连接。  

  3. SQL> shutdown immediate  

  4. 数据库已经关闭。  

  5. 已经卸载数据库。  

  6. ORACLE 例程已经关闭。  

  7. SQL> startup  

  8. ORACLE 例程已经启动。  

  9.   

  10. Total System Global Area 167772160 bytes  

  11. Fixed Size 1247900 bytes  

  12. Variable Size 67110244 bytes  

  13. Database Buffers 96468992 bytes  

  14. Redo Buffers 2945024 bytes  

  15. 数据库装载完毕。  

  16. 数据库已经打开。  

  17. SQL> connect xys/manager  

  18. 已连接。  

  19. SQL> drop table tt;  

  20.   

  21. 表已删除。  

  22.   

  23. SQL> create table tt(id int , name varchar2(10));  

  24.   

  25. 表已创建。  

  26. SQL> col name format a30  

  27. SQL> select a.*,b.name  

  28. 2 from v$sesstat a , v$statname b  

  29. 3 where a.statistic#=b.statistic#  

  30. 4 and a.sid=(select distinct sid from v$mystat)  

  31. 5 and b.name like '%parse%';  

  32.   

  33. SID STATISTIC# VALUE NAME  

  34. ---------- ---------- ---------- ------------------------------  

  35. 159 328 39 parse time cpu  

  36. 159 329 74 parse time elapsed  

  37. 159 330 339 parse count (total)  

  38. 159 331 165 parse count (hard)  

  39. 159 332 0 parse count (failures)  

  40.   

  41. SQL> declare  

  42. 2 begin  

  43. for i in 1..100 loop  

  44. 4 insert into tt values(i,'test');  

  45. 5 end loop;  

  46. 6 commit;  

  47. 7 end;  

  48. 8 /  

  49.   

  50. PL/SQL 过程已成功完成。  

  51.   

  52. SQL> select a.*,b.name  

  53. 2 from v$sesstat a , v$statname b  

  54. 3 where a.statistic#=b.statistic#  

  55. 4 and a.sid=(select distinct sid from v$mystat)  

  56. 5 and b.name like '%parse%'  

  57. 6 /  

  58.   

  59. SID STATISTIC# VALUE NAME  

  60. ---------- ---------- ---------- ------------------------------  

  61. 159 328 39 parse time cpu  

  62. 159 329 74 parse time elapsed  

  63. 159 330 345 parse count (total)  

  64. 159 331 167 parse count (hard)  

  65. 159 332 0 parse count (failures)  

  66.   

  67. SQL>  



这里发现hard parse只增加了2,如果没有使用绑定变量的话,相信hard parse会更多



4.

过程中的参数会自动转化为绑定变量

[c-sharp] view plaincopy

  1. SQL> edit  

  2. 已写入 file afiedt.buf  

  3.   

  4. 1 create or replace procedure proc_test(p_id int, p_name varchar2)  

  5. is  

  6. 3 begin  

  7. 4 insert into tt values(p_id , p_name);  

  8. 5 commit;  

  9. 6* end;  

  10. SQL> /  

  11.   

  12. 过程已创建。  

  13.   

  14. SQL> alter session set sql_trace=true;  

  15.   

  16. 会话已更改。  

  17.   

  18. SQL> exec proc_test(200,'test');  

  19.   

  20. PL/SQL 过程已成功完成。  

  21.   

  22. SQL> alter session set sql_trace=false;  

  23.   

  24. 会话已更改。  

  25. --trace file:  

  26. alter session set sql_trace=true  

  27. END OF STMT  

  28. EXEC #3:c=0,e=749,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=7393908487  

  29. =====================  

  30. PARSING IN CURSOR #1 len=35 dep=0 uid=31 oct=47 lid=31 tim=7403000735 hv=526484776   

  31.   

  32. ad='6687b0b8'  

  33. BEGIN proc_test(200,'test'); END;  

  34. END OF STMT  

  35. PARSE #1:c=0,e=2584,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=7403000727  

  36. =====================  

  37. PARSING IN CURSOR #6 len=33 dep=1 uid=31 oct=2 lid=31 tim=7403001293 hv=2874748229   

  38.   

  39. ad='668e9cd8'  

  40. INSERT INTO TT VALUES(:B2 , :B1 )  

  41. END OF STMT  

  42. PARSE #6:c=0,e=246,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,tim=7403001286  

  43. =====================  


另外也可以直观的观察:

[c-sharp] view plaincopy

  1. SQL> exec proc_test(200,'test');  

  2.   

  3. PL/SQL 过程已成功完成。  

  4.   

  5. SQL> select sql_text from v$sql where sql_text like '%proc_test%';  

  6.   

  7. SQL_TEXT  

  8. --------------------------------------------------------------------------------  

  9. BEGIN proc_test(200,'test'); END;  

  10.   

  11. SQL>  


sqlplus里执行过程不能观察出来
下面在plsql developer执行一次过程之后再来看执行的情况

[c-sharp] view plaincopy

  1. SQL> select sql_text from v$sql where sql_text like '%proc_test%';  

  2.   

  3. SQL_TEXT  

  4. --------------------------------------------------------------------------------  

  5. begin -- Call the procedure proc_test(p_id =>:p_id, p_name =>:p_name); end;  

  6.   

  7. SQL>  


很显然oracle在执行过程时把参数转化为绑定变量了,其实从plsql developer中执行过程时的语法就能

看出来:

[c-sharp] view plaincopy

  1. begin  

  2. -- Call the procedure  

  3. proc_test(p_id => :p_id,  

  4. p_name => :p_name);  

  5. end;  


在输入参数列表框上面的执行语法就是这样的。




5.

在动态sql中使用绑定变量,动态sql中使用绑定变量非常明显也容易理解,下面给出2个简单的例子

[c-sharp] view plaincopy

  1. SQL> set serveroutput on  

  2. SQL> declare  

  3.    2   v_string varchar2(100);  

  4.    3   v_id tt.id%type ;  

  5.    4   v_name tt.name%type ;  

  6.    5   begin  

  7.    6   v_string:='select * from tt where id=:v_id';  

  8.    7   execute immediate v_string into v_id , v_name using &a;  

  9.    8   dbms_output.put_line(v_id||' '||v_name) ;  

  10.    9   end;  

  11. 10   /  

  12. 输入 a 的值:   1  

  13. 原值 7: execute immediate v_string into v_id , v_name using &a;  

  14. 新值 7: execute immediate v_string into v_id , v_name using 1;  

  15. 1 test  

  16.   

  17. PL/SQL 过程已成功完成。  

  18.   

  19. SQL> declare  

  20.    2   v_string varchar2(100);  

  21.    3   v_id tt.id%type;  

  22.    4   v_name tt.name%type ;  

  23.    5   begin  

  24.    6   v_string:='insert into tt values(:id,:name)';  

  25.    7   execute immediate v_string using &id,&name ;  

  26.    8   end;  

  27.    9   /  

  28. 输入 id 的值:   1000  

  29. 输入 name 的值:   'test'  

  30. 原值 7: execute immediate v_string using &id,&name ;  

  31. 新值 7: execute immediate v_string using 1000,'test' ;  

  32.   

  33. PL/SQL 过程已成功完成。  

  34.   

  35. SQL> select * from tt where id=1000;  

  36.   

  37. ID NAME  

  38. ---------- ----------  

  39.    1000 test  

  40.   

  41. SQL>  



=============================下面加上一些其他变量的使用方法========================= 



eg001&替换变量)



[c-sharp] view plaincopy

  1. SQL> select xh,xm from system.xs where zym='&zym';  

  2. 输入 zym 的值:  计算机  

  3. 原值 1: select xh,xm from system.xs where zym='&zym'  

  4. 新值 1: select xh,xm from system.xs where zym='计算机'  

  5.   

  6. XH XM  

  7. ------ --------  

  8. 061101 王林  

  9. 061102 程明  

  10. 061103 王燕  

  11. 061104 韦严平  

  12. 061106 李方方  

  13. 061107 李明  

  14. 061108 林一帆  

  15. 061109 张强民  

  16. 061110 张蔚  

  17. 061111 赵琳  

  18. 061113 严红  

  19.   

  20. 已选择11行。  

  21.   

  22. SQL> edit  

  23. 已写入 file afiedt.buf  

  24.   

  25.   1  select xh 学号,xm 姓名,avg(cj) as 平均成绩  

  26.   2* from system.xs_xkb group by xh,xm  

  27. SQL> /  

  28.   

  29. 学号   姓名 平均成绩  

  30. ------ -------- ----------  

  31. 061103 王燕 71  

  32. 061210 李红庆 76  

  33. 061110 张蔚 91.3333333  

  34. 061220 吴薇华 82  

  35. 061104 韦严平   79.6666667  

  36. 061101 王林 78  

  37. 061204 马林林 91  

  38. 061106 李方方 72  

  39. 061218 孙研 70  

  40. 061102 程明 78  

  41. 061241 罗林琳 90  

  42.   

  43. 学号   姓名 平均成绩  

  44. ------ -------- ----------  

  45. 061111 赵琳 80.5  

  46. 061109 张强民 76.5  

  47. 061216 孙祥欣 81  

  48. 061221 刘燕敏 79  

  49.   

  50. 已选择15行。  

  51.   

  52. SQL> select * from system.xs_xkb where cj>=&cj; /*替换变量可以使用WHERE子句;ORDER BY子句;列表达式;表名;整个SELECT语句*/  

  53. 输入 cj 的值:  90  

  54. 原值 1: select * from system.xs_xkb where cj>=&cj  

  55. 新值 1: select * from system.xs_xkb where cj>=90  

  56.   

  57. SQL> select xs.xh,&name,kcm,&column  

  58.   2  from system.xs,&kc,system.xs_kc  

  59.   3  where xs.xh=xs_kc.xh and &condition  

  60.   4  and kcm=&kcm  

  61.   5  order by & column;  

  62. 输入 name 的值:  xm  

  63. 输入 column 的值:  cj  

  64. 原值 1: select xs.xh,&name,kcm,&column  

  65. 新值 1: select xs.xh,xm,kcm,cj  

  66. 输入 kc 的值:  system.kc  

  67. 原值 2: from system.xs,&kc,system.xs_kc  

  68. 新值 2: from system.xs,system.kc,system.xs_kc  

  69. 输入 condition 的值:  kc.kch=xs_kc.kch  

  70. 原值 3: where xs.xh=xs_kc.xh and &condition  

  71. 新值 3: where xs.xh=xs_kc.xh and kc.kch=xs_kc.kch  

  72. 输入 kcm 的值:  '离散数学'  

  73. 原值 4: and kcm=&kcm  

  74. 新值 4: and kcm='离散数学'  

  75. 输入 column 的值:  cj  

  76. 原值 5: order by & column  

  77. 新值 5: order by cj  

  78.   

  79. XH XM KCM CJ  

  80. ------ -------- ---------------- ----------  

  81. 061104 韦严平   离散数学 65  

  82. 061109 张强民   离散数学 70  

  83. 061101 王林 离散数学 76  

  84. 061102 程明 离散数学 78  

  85. 061106 李方方   离散数学 80  

  86. 061103 王燕 离散数学 81  

  87. 061110 张蔚 离散数学 89  



eg002&&替换变量)



[c-sharp] view plaincopy

  1. --&&替换变量系统一直用同一个值处理,清除用undefine 变量名清除  

  2. SQL> edit  

  3. 已写入 file afiedt.buf  

  4.   

  5.   1  select xs.xh,&name,kcm,&&column   /*清除替换变量(undefine column)*/  

  6.   2  from system.xs,&kc,system.xs_kc  

  7.   3  where xs.xh=xs_kc.xh and &condition  

  8.   4  and kcm=&kcm  

  9.   5* order by &column  

  10. SQL> /  

  11. 输入 name 的值:  xm  

  12. 输入 column 的值:  cj  

  13. 原值 1: select xs.xh,&name,kcm,&&column  

  14. 新值 1: select xs.xh,xm,kcm,cj  

  15. 输入 kc 的值:  system.kc  

  16. 原值 2: from system.xs,&kc,system.xs_kc  

  17. 新值 2: from system.xs,system.kc,system.xs_kc  

  18. 输入 condition 的值:  kc.kch=xs_kc.kch  

  19. 原值 3: where xs.xh=xs_kc.xh and &condition  

  20. 新值 3: where xs.xh=xs_kc.xh and kc.kch=xs_kc.kch  

  21. 输入 kcm 的值:  '离散数学'  

  22. 原值 4: and kcm=&kcm  

  23. 新值 4: and kcm='离散数学'  

  24. 原值 5: order by &column /*使用&&替换变量的好处,相同变量只输第一次就OK*/  

  25. 新值 5: order by cj  

  26.   

  27. XH XM KCM CJ  

  28. ------ -------- ---------------- ----------  

  29. 061104 韦严平   离散数学 65  

  30. 061109 张强民   离散数学 70  

  31. 061101 王林 离散数学 76  

  32. 061102 程明 离散数学 78  

  33. 061106 李方方   离散数学 80  

  34. 061103 王燕 离散数学 81  

  35. 061110 张蔚 离散数学 89  

  36.   

  37. 已选择7行。  


eg003


DEFINE[variable[=value]]
UNDEFINE
清除定义的变量

[c-sharp] view plaincopy

  1. SQL> define specialty=通信工程  

  2. SQL> define specialty  

  3. DEFINE SPECIALTY = "通信工程" (CHAR)  

  4. SQL> select xh,xm,xb,cssj,zxf from system.xs  

  5.   2  where zym='&specialty';  

  6.   

  7. XH XM XB CSSJ ZXF  

  8. ------ -------- -- -------------- ----------  

  9. 061202 王林 男 29-10月-85 40  

  10. 061210 李红庆   女 01-5月 -85 44  

  11. 061201 王敏 男 10-6月 -84 42  

  12. 061203 王玉民   男 26-3月 -86 42  

  13. 061204 马林林   女 10-2月 -84 42  

  14. 061206 李计 女 20-9月 -85 42  

  15. 061216 孙祥欣   女 09-3月 -84 42  

  16. 061218 孙研 男 09-10月-86 42  

  17. 061220 吴薇华   女 18-3月 -86 42  

  18. 061221 刘燕敏   女 12-11月-85 42  

  19. 061241 罗林琳   女 30-1月 -86 50  

  20.   

  21. 已选择11行。  



eg004
ACCEPT variable[datatype[NUMBER|CHAR|DATE]][FORMAT format][PROMPT text][HIDE]
/*variable
:指定接收值的变量。该名称的变量不存在,那么SQL重建该变量;datatype:变量数据类型,默认为CHAR*/



[c-sharp] view plaincopy

  1. SQL> accept num prompt'请输入课程号:'  

  2. 请输入课程号:101  

  3. SQL> set verify on  

  4. SQL>   

  5.   1  select xh,kcm,cj from system.xs_kc,system.kc  

  6.   2  where xs_kc.kch=kc.kch and kc.kch='&num'  

  7.   3* order by cj  

  8. SQL> /  

  9. 原值 2: where xs_kc.kch=kc.kch and kc.kch='&num'  

  10. 新值 2: where xs_kc.kch=kc.kch and kc.kch='101'  

  11.   

  12. XH KCM CJ  

  13. ------ ---------------- ----------  

  14. 061103 计算机基础 62  

  15. 061106 计算机基础 65  

  16. 061218 计算机基础 70  

  17. 061210 计算机基础 76  

  18. 061221 计算机基础 79  

  19. 061101 计算机基础 80  

  20. 061216 计算机基础 81  

  21. 061220 计算机基础 82  

  22. 061241 计算机基础 90  

  23. 061104 计算机基础 90  

  24. 061111 计算机基础 91  

  25.   

  26. XH KCM CJ  

  27. ------ ---------------- ----------  

  28. 061204 计算机基础 91  

  29. 061110 计算机基础 95  

  30.   

  31. 已选择13行。  

  32.   

  33. SQL>  



转载于:

https://blog.51cto.com/9048865/1586275

来自 https://www.huaweicloud.com/articles/e1d39967576550574f3a2b065d00fd44.html


普通分类: