oracle笔记-动态SQL
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle笔记-动态SQL相关的知识,希望对你有一定的参考价值。
参考技术A第 章 动态SQL
为何使用动态SQL
实现动态SQL有两种方式 DBMS_SQL和本地动态SQL(EXECUTE IMMEIDATE)
主要从以下方面考虑使用哪种方式
是否知道涉及的列数和类型
DBMS_SQL包括了一个可以 描述 结果集的存储过程(DBMS_SQL DESCRIBE_COLUMNS) 而本地动态SQL没有
是否知道可能涉及的绑定变量数和类型
DBMS_SQL允许过程化的绑定语句的输入 而本地动态SQL需要在编译时确定
是否使用 数组化 操作(Array Processing)
DBMS_SQL允许 而本地动态SQL基本不可以 但可以用其他方式实现(对查询可用FETCH BULK COLLECT INTO 对INSERT等 可用一个BEGIN … END块中加循环实现)
是否在同一个会话中多次执行同一语句
DBMS_SQL可以分析一次执行多次 而本地动态SQL会在每次执行时进行软分析
是否需要用REF CURSOR返回结果集
仅本地动态SQL可用REF CURSOR返回结果集
如何使用动态SQL
DBMS_SQL
调用OPEN_CURSOR获得一个游标句柄
调用PARSE分析语句 一个游标句柄可以用于多条不同的已分析语句 但一个时间点仅一条有效
调用BIND_VARIABLE或BIND_ARRAY来提供语句的任何输入
若是一个查询(SELECT语句) 调用DIFINE_COLUMN或DEFINE_ARRAY来告知Oracle如何返回结果
调用EXECUTE执行语句
若是一个查询 调用FETCH_ROWS来读取数据 可以使用COLUMN_VALUE从SELECT列表根据位置获得这些值
否则 若是一个PL/SQL块或带有RETURN子句的DML语句 可以调用VARIABLE_VALUE从块中根据变量名获得OUT值
调用CLOSE_CURSOR
注意这里对任何异常都应该处理 以关闭游标 防止泄露资源
本地动态SQL
EXECUTE IMMEDIATE 语句
[INTO 变量 变量 … 变量N | 记录体]
[USING [IN | OUT | IN OUT] 绑定变量 … 绑定变量N]
[RETURNING | RETURN INTO 输出 [ … 输出N]…]
注意本地动态SQL仅支持弱类型REF CURSOR 即对于REF CURSOR 不支持BULK COLLECT
最后说明
lishixinzhi/Article/program/Oracle/201311/18948
Oracle之PL/SQL学习笔记
自己在学习Oracle是做的笔记及实验代码记录,内容挺全的,也挺详细,发篇博文分享给需要的朋友,共有1w多字的学习笔记吧。是以前做的,一直在压箱底,今天拿出来整理了一下,给大家分享,有不足之处还望大家批评指正。
PL/SQL定义:PL/SQL是由Oracle开发,专门用于Oracle的程序设计语言。 PL---Procedural Language. SQL—Structure QueryLanguage。PL/SQL包括过程化语句和SQL语句
PL/SQL的单位:块。 一个块中可以嵌套子块。
块的三个组成部分:
一:定义部分(declare)
PL/SQL中使用的变量,常量,游标和异常的名字都必须先定义后使用。并且定义在以declare关键字开头的定义部分
二:可执行部分:(begin)
是PL/SQL的主题,包含该块的可执行语句,该部分定义了块的功能,是必须的部分。由关键字begin开始,end结束
三:异常处理部分:(exception)
该部分以exception开始,以end结束
Demo: DECLARE –可选 变量,常量,游标,用户自定义的特殊类型 BEGIN –必须 --SQL语句 --PL/SQL语句 EXCEPTION –可选 --异常处理部分 END; --必须 即由声明,执行,异常组成
DEMO: DECLARE V_value1 VARCHAE2(5); BEGIN SELECT cn_name INTO v_value1 FROM table_name; EXCEPTION WHEN exception_name THEN --处理程序…… END;
PL/SQL的优点:
1、 改善了性能:PL/SQL把整个语句块发送给服务器,这个过程在单次调用中完成,降低了网络拥挤
2、 可重用性:只要有Oracle的地方都能运行
3、 模块化:程序中的每一块都实现一个逻辑操作,有效的进行了分割。
PL/SQL块的类:
1、 匿名块:只能存储一次,不能存储在数据库中
2、 过程,函数和包(procedure,function,package):是命了名的PL/SQL块,被存储在数据库中,可以被多次使用,可以用外部程序显示执行。
3、 触发器:是命名的PL/SQL块,被存储在数据库中,当触发某事件时自动执行。
PL/SQL中变量的命名规范:
1、 至多有30个字符
2、 不能是保留字
3、 必须以字母开头
4、 不允许和数据库中表的列名相同
5、 不可包括$,_和数字以外的字符
PL/SQL中的变量
1、 PL/SQL变量
a) 标量型:只能存放单一值
b) 复合型
c) 引用型
d) LOBx型:存放大数据
2、 定义变量语法
a) 变量名 变量类型 := 变量值
b) V_number NUMBER(2) NOT NULL :=20;
c) 常量的定义
i. V_number CONSTANT
NUMBER(2,3) :=20.098;
1 DEMO:查询员工号为7369的员工,把其job存入v_job中并输出 2 DECLARE 3 --定义存储job的变量v_job为引用变量与--emp.job的类型相同,用%TYPE实现 4 v_job emp.job%TYPE; 5 --定义员工号变量并赋初值(:=) 6 n_empno emp.empno%TYPE:=7369; 7 BEGIN 8 --查询语句 9 SELECT emp.job 10 --把查出来的结果赋给v_job 11 INTO v_job 12 FROM emp 13 WHERE emp.empno = n_empno; 14 --打印输出结果 15 Dbms_Output.put_line(v_job); 16 END;
%TYPE属性:
通过%TYPE声明一个变量,实际上就是参照变量或表中的字段的类型作为变量的类型,并且保持同步。
变量将遵循下面的类型声明:
1. 已声明过的变量类型
2. 数据库中表字段的类型
demo1:
创建一个匿名块,输出hello world
1 --创建一个匿名块,输出hello world 2 DECLARE 3 v_hello varchar2(20) :=‘Hello World‘; 4 BEGIN 5 Dbms_Output.put_line(v_hello); 6 END; 7 8 --创建一个匿名块,查询emp表,显示雇员名是’SCOTT‘的薪水,通过DBMS_OUTPUT包来显示。 9 DECLARE 10 v_sal emp.sal%TYPE; 11 v_name emp.ename%TYPE := ‘SCOTT‘; 12 BEGIN 13 SELECT emp.sal 14 INTO v_sal 15 FROM emp 16 WHERE emp.ename = v_name; 17 dbms_output.put_line(v_sal); 18 END;
demo2:
-从部门表中找到最大的部门号,将其输出到屏幕
1 --从部门表中找到最大的部门号,将其输出到屏幕 2 DECLARE 3 v_deptno dept.deptno%TYPE; 4 BEGIN 5 SELECT MAX(dept.deptno) 6 INTO v_deptno 7 FROM dept; 8 dbms_output.put_line(v_deptno); 9 END;
demo3:
--PL/SQL嵌套和变量的作用域
--PL/SQL嵌套和变量的作用域 DECLARE v_parent NUMBER :=10; BEGIN DECLARE v_child NUMBER :=20; BEGIN dbms_output.put_line(‘chile=‘||v_child); dbms_output.put_line(‘parent=‘||v_parent); END; --dbms_output.put_line(‘chile=‘||v_child); --注意变量的作用域 dbms_output.put_line(‘chile=‘||v_parent); END; 结果: chile=20 parent=10 chile=10
demo4:
--选择并打印emp表中薪水总和
1 --选择并打印emp表中薪水总和 2 DECLARE 3 v_sal emp.sal%TYPE; 4 BEGIN 5 SELECT sum(emp.sal) 6 INTO v_sal 7 FROM emp; 8 dbms_output.put_line(v_sal); 9 END
demo5:事务的操作
1 DECLARE 2 v_sal emp.sal%TYPE :=800; 3 BEGIN 4 UPDATE emp 5 SET emp.sal = emp.sal+ v_sal 6 WHERE emp.job=‘ANALYST‘; 7 SAVEPOINT a; 8 UPDATE emp 9 SET emp.sal = emp.sal+ v_sal 10 WHERE emp.job=‘ANALYST‘; 11 SAVEPOINT b; 12 ROLLBACK TO SAVEPOINT a; 13 COMMIT; 14 END;
编写控制结构
1、 条件分支语句
a) IF语句:
- i. – IF – THEN – END IF
- ii. – IF – THEN – ELSE – END IF
- iii. – IF – THEN – ELSEIF – END IF
2、 条件语句语法
a) IF condition THEN
i. Statement;
b) [ELSIF condition THEN
i. Statement;]
c) [ELSE
i. Statement;]
d) ENDIF;
3、 DEMO:
a) IF v_name = ‘SCOTT’ AND SAL >= 3000 THEN
i. v_dept :=20;
b) END IF;
1 DEMO: 2 --null的处理 3 DECLARE 4 v_x NUMBER :=NULL; 5 v_y NUMBER := NULL; 6 BEGIN 7 IF v_x = v_y THEN 8 dbms_output.put_line(‘NULL等于NULL‘); 9 ELSE 10 dbms_output.put_line(‘NULL不等于NULL‘); 11 END IF; 12 END; 13 结果:NULL不等于NULL 空是未知的东西
4.Case语句:语法(有返回值的)
1 CASE demo: 2 DECLARE 3 v_sal emp.sal%TYPE; 4 v_dept emp.deptno%TYPE; 5 v_result VARCHAR(20); 6 BEGIN 7 SELECT emp.deptno 8 INTO v_dept 9 FROM emp 10 WHERE emp.sal = 11 ( 12 SELECT MAX(emp.sal) 13 FROM emp 14 ); 15 dbms_output.put_line(v_dept); 16 v_result := 17 CASE v_dept 18 WHEN 10 THEN ‘部门一‘ 19 WHEN 20 THEN ‘部门二‘ 20 ELSE ‘部门三‘ 21 END; 22 dbms_output.put_line(v_result); 23 END; 24 输出结果: 25 10 26 部门一
5、 循环语句LOOP :
DEMO:循环插入11条数据
1 DECLARE 2 v_count NUMBER := 0; 3 BEGIN 4 LOOP 5 --插入数据 6 INSERT INTO 7 test(name,id,password) 8 VALUES (‘TEST‘||v_count,v_count,‘admin‘); 9 --变量加一 10 v_count := v_count+1; 11 --判断退出条件 12 EXIT WHEN v_count > 10; 13 END LOOP; 14 END;
b) FOR LOOP循环
1 DEMO: 2 DECLARE 3 v_counter NUMBER :=0; 4 BEGIN 5 --v_counter是自增的 6 FOR v_counter IN 0 .. 10 LOOP 7 DELETE FROM test 8 WHERE test.id = v_counter; 9 END LOOP; 10 END;
b) WHILE LOOP
1 DECLARE 2 v_count NUMBER := 0; 3 BEGIN 4 WHILE v_count<10 LOOP 5 --插入数据 6 INSERT INTO 7 test(name,id,password) 8 VALUES (‘TEST‘||v_count,v_count,‘admin‘); 9 --变量加一 10 v_count := v_count+1; 11 END LOOP; 12 END;
三:复合类型
1、 复合数据类型
a) 一个复合变量可以存放多个值
b) 复合变量创建后可以多次使用
c) 如同枚举类型和数组
2、 PL/SQL记录
a) 每个记录内都有很多的不同类型的字段
b) 无初始值的字段为NULL
c) Record 类型声明用户自定义的类型
3、 定义一个记录
a) 语法:
1 i. TYPE type_name IS RECORD( 2 ii. 字段名1 字段类型1, 3 iii. 字段名2 字段类型2 4 iv. );
b) DEMO
i. TYPE emp_record_name IS RECORD( ii. V_name varchar(20), iii. V_password varchar(10) iv. ); v. Emp_record emp_record_name;
--记录的定义与使用 DECLARE TYPE test_record_name IS RECORD( v_name test.name%TYPE, v_id test.id%TYPE, v_password test.password%TYPE ); test_record test_record_name; BEGIN SELECT test.name,test.id,test.password INTO test_record FROM test WHERE test.name=‘TEST0‘; dbms_output.put_line(test_record.v_name||test_record.v_id||test_record.v_password); END;
5 记录的另一种定义:表名%ROWTYPE
a) Exp_row table_name%ROWTYPE
DEMO:
1 --记录的定义与使用 2 DECLARE 3 emp_record emp%ROWTYPE; 4 5 BEGIN 6 SELECT * 7 INTO emp_record 8 FROM emp 9 WHERE emp.empno=‘7788‘; 10 dbms_output.put_line(emp_record.empno||‘ ‘||emp_record.sal); 11 END;
编写游标
1、 游标的定义:游标是Oracle在数据库中开辟的一个工作区,用来存放SELECT语句查询的结果。
2、 游标的分类
a) 隐式游标:PL/SQL隐式建立并管理这一游标。
b) 显示游标:由程序员定义并控制,从数据库中读出多行数据,并从多行数据中一行一行的处理。
3、 游标的声明:
a) 语法:CURSOR cursor_name IS select_statement;
b) 在游标声明中SELECT语句不能使用INTO语句,可以在字句子中使用ORDER字句。
c) Demo:
1 CURSOR emp_cursor IS 2 SELECT * 3 FROM emp;
4、 打开游标
a) 语法:OPEN cursor_name;
b) 使用游标之前应打开游标
c) 打开游标实际上是执行定义游标时的SELECT语句,将查询结果检索到工作区中。
d) 如果没有要返回的行没有异常
5、 从游标中提取数值
a) 语法
i. FETCH cursor_name INTO [v1,v2……]|record_name]
b) 在使用FETCH时先把游标打开,不然没法使用。
c) 对游标第一次使用FETCH时,游标指向的是第一条记录,使用后游标指向下一条记录。
d) 游标只能向下移动不能回退,如果想回退到上一条记录,只有把游标关闭后在打开。
e) INTO字句中的变量个数、顺序、数据类型必须和工作区中的保持一致;
6、 关闭游标
a) 语法:CLOSE cursor_name
b) 处理完数据后必须关闭游标,如果需要可以再次打开游标,游标一旦关闭不可再从游标中提取数据,当关闭游标后所有和游标相关的资源都会被关闭。
7.游标的使用Demo
1 --游标的使用 2 DECLARE 3 --定义临时变量来存放游标中的内容 4 emp_empno emp.empno%TYPE; 5 emp_ename emp.ename%TYPE; 6 --定义名为emp_cursor的游标 7 CURSOR emp_cursor IS 8 SELECT emp.empno,emp.ename 9 FROM emp; 10 BEGIN 11 --打开游标 12 OPEN emp_cursor; 13 --循环输出游标 14 FOR i IN 1..5 LOOP 15 --提取游标中的内容 16 FETCH emp_cursor 17 INTO emp_empno,emp_ename; 18 dbms_output.put_line(emp_empno||‘ ‘||emp_ename); 19 END LOOP; 20 --关闭游标 21 CLOSE emp_cursor; 22 END;
以上是关于oracle笔记-动态SQL的主要内容,如果未能解决你的问题,请参考以下文章
PL/SQL Oracle :- 在传递值时动态 UNPIVOT ORACLE TABLE