PL/SQL
2015-12-12 21:36
381 查看
/* 什么是PL/SQL? (1)PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言。 (2)PL/SQL 是对 SQL 的扩展。 (3)支持多种数据类型,如大对象和集合类型,可使用条件和循环等控制结构。 (4)可用于创建存储过程、函数、触发器和程序包,给SQL语句的执行添加程序逻辑。 优点: (1)支持 SQL,在 PL/SQL 中可以使用: a) 数据操纵命令:DML,DDL b) 事务控制命令:TCL c) 游标控制 d) SQL函数和SQL运算符 (2)与 SQL 紧密集成,简化数据处理。 a) 支持所有 SQL 数据类型 b) 支持 NULL 值 c) 支持 %TYPE(引用字段类型:employee.ename%TYPE)和 %ROWTYPE(引用表的行类型:employee%TYPE)属性类型 (3)支持面向对象编程 (OOP) (4)可移植性,可运行在任何操作系统和平台上的Oralce 数据库 (5)更佳的性能,PL/SQL 经过编译执行 PL/SQL基本单元分为三个部分:1)声明部分declare(可选)。 2)可执行部分。3)异常处理部分(可选)。 PL/SQL语法: [DECLARE 声明变量、常量、游标、自定义记录类型等。 ] BEGIN 执行部分。 [EXCEPTION 异常处理部分。 ] END; 中括号括起的部分为可选部分。 变量与常量的声明和使用: (1) 在声明部分声明,使用前必须先声明。 (2) 声明时必须指定数据类型,每行声明一个标识符。 (3) 在可执行部分的 SQL 语句和过程语句中使用。 语法: identifier [CONSTANT] datatype [NOT NULL] [:= value]; 或。 identifier [CONSTANT] datatype [NOT NULL] [DEFAULT expr]; 给变量赋值有两种方式: (1) 使用赋值运算符" := " (2) 使用: SELECT column_list INTO variable_list FROM table ....语句 如果PL/SQL拿到命令行去执行看不到输出的话,需要用以下命令打oracle服务端输出, 否则PL/SQL、过程等的输出是看不到的: set serveroutput on; */ --1. 最简单的PL/SQL块 declare --没有声明变量等 begin dbms_output.put('hello '); --将内容放入到输出缓存中,不会立即输出内容 dbms_output.put_line('PL/SQL!');--立即输出内容 end; / --变量的声明和使用 declare --identifier [CONSTANT] datatype [NOT NULL] [:= value]; v_ename varchar2(20) := 'james zhang'; v_ename2 varchar2(20) default 'zhang san'; v_empno int; begin -- "&"号在PL/SQL中表示替代变量,可用它来在运行时接收输入值,如果输入的值字符串则用单引号括起来 v_ename := '&请输入姓名:'; v_empno := &请输入编号; dbms_output.put_line(v_ename); dbms_output.put_line(v_ename2); dbms_output.put_line(v_empno); end; / --使用类型引用方式来声明变量 declare v_empno employee.empno%TYPE; v_ename employee.ename%type; v_sal employee.sal%type; --声明一个能存储employee行类型的变量 rec_emp employee%rowtype; --接收输入的值 v_in_empno employee.empno%TYPE; begin v_in_empno := &请输入员工编号; /*通过查询记录来给变量赋值 SELECT column_list INTO variable_list FROM table ....语句, 只能返回一行,如果多行会报异常 */ select empno,ename,sal into v_empno,v_ename,v_sal from employee where empno=v_in_empno; --输出 dbms_output.put_line('编号:'||v_empno||',姓名:'||v_ename||',工资:'||v_sal); --查询记录为行类型变量赋值 select * into rec_emp from employee where empno=v_in_empno; dbms_output.put_line('==>>编号:'||rec_emp.empno||',姓名:'||rec_emp.ename||',工资:'||rec_emp.sal); end; / /* (二) PL/SQL 支持的流程控制结构: a) 条件控制 i. IF、IF-ELSE 语句 ii. CASE 语句 b) 循环控制 i. LOOP 循环 ii. WHILE 循环 iii. FOR 循环 (三) 顺序控制 a) GOTO 语句 b) NULL (四) NULL 语句 (五) 异常处理 a)Oracle预定义异常 b)自定义异常 */ /* a) 条件控制: if, if-else i. IF 、IF-ELSE 语句 语法: IF <condition> THEN statement.... [ELSE] statement.... END IF; 每一个if都必须对应的有一个end if; */ --根据某员工薪资情况对薪资做出调整:?<3000的加500,?>3000的加250, declare v_empno employee.empno%type; v_sal employee.sal%type; begin v_empno := &请输入员工编号:; --如果查询无数据时给变量赋值会有异常 select sal into v_sal from employee where empno=v_empno; dbms_output.put_line('编号:'||v_empno||'的员工工资是:'||v_sal); if v_sal<=3000.0 then update employee set sal=sal+500 where empno=v_empno; else update employee set sal=sal+250 where empno=v_empno; end if; commit; --提交事务 select sal into v_sal from employee where empno=v_empno; dbms_output.put_line('更新后,编号:'||v_empno||'的员工工资是:'||v_sal); --异常处理 exception when NO_DATA_FOUND then dbms_output.put_line('员工:'||v_empno||'不存在。'); when others then --相当于java的Exception dbms_output.put_line('更新员工:'||v_empno||'失败。'); end; / --多重IF-ELSE 判断学生成绩,显示:80>=优秀,70<=良好<80,60<=及格<70,60>不及格 declare v_score integer; begin v_score := &请输入学生成绩:; if v_score>=80 then dbms_output.put_line('优秀:'||v_score); else if v_score>=70 then dbms_output.put_line('良好:'||v_score); else if v_score>=60 then 101de dbms_output.put_line('及格:'||v_score); else dbms_output.put_line('不及格:'||v_score); end if; end if; end if; end; / /* a) 条件控制: CASE ii. CASE 语句 */ --判断学生成绩 --case 第1种用法:可用来匹配数值范围 declare v_score integer; begin v_score := &请输入学生成绩:; case when v_score>=80 then dbms_output.put_line('优秀:'||v_score); when v_score>=70 then dbms_output.put_line('良好:'||v_score); when v_score>=60 then dbms_output.put_line('及格:'||v_score); else dbms_output.put_line('不及格:'||v_score); end case; end; / --case第2种 用法:只能精确匹配值(匹配一个常量值) declare v_score char(1); begin v_score := upper('&请输入学生成绩:'); case v_score when 'A' then dbms_output.put_line('优秀:'||v_score); when 'B' then dbms_output.put_line('良好:'||v_score); when 'C' then dbms_output.put_line('及格:'||v_score); else dbms_output.put_line('不及格:'||v_score); end case; end; / /* b) 循环控制:LOOP, WHILE, FOR i. LOOP 无条件循环 语法: LOOP statement...; IF 条件 THEN EXIT; END IF; 或用[EXIT WHEN 条件;] END LOOP; 在循环体内可通过:EXIT,或 EXIT WHEN 条件 来退出循环。 */ --打印输出格式:1,2,3.....10 declare i int := 1; begin loop dbms_output.put(i); --不换行, dbms_output.put_line();--会换行输出 if i<=9 then dbms_output.put(','); end if; exit when i=10; i := i+1; end loop; dbms_output.new_line; --输出缓存的内容 end; / /* 打印直角三角形(一行一列,二行二列....) * ** *** **** ***** ****** ******* */ declare v_row int := 1; v_col int := 0; v_line int; begin v_line := &请输入行数:; loop v_col := 0; loop if v_col<v_row then dbms_output.put('*'); end if; exit when v_col=v_row; v_col := v_col+1; end loop; dbms_output.new_line; exit when v_row=v_line; --10行 v_row := v_row + 1; end loop; end; / /* b) WHILE 循环控制 i. LOOP 无条件循环 ii. WHILE 循环: 有条件循环。 WHILE语法: WHILE 条件 LOOP statement; [EXIT WHEN 条件;] END LOOP; 在循环体内也可通过:EXIT, EXIT WHEN 条件 来使循环退出。 * *** ***** ******* 4-line print 2*line-1 */ declare v_row int := 1; v_col int := 0; v_blank int := 0; begin while v_row<=4 loop v_blank := 0; --输出空格 while v_blank<(4-v_row) loop dbms_output.put(' '); v_blank := v_blank+1; end loop; v_col := 0; --输出*号 while v_col<(2*v_row-1) loop dbms_output.put('*'); v_col := v_col+1; end loop; dbms_output.new_line;--换行 v_row := v_row+1; end loop; end; / /* b) FOR 循环控制 i. LOOP 循环 ii. WHILE 循环 iii. FOR 循环:有次数的循环。 FOR语法: FOR 计数器变量(oracle自动创建无需预先声明) IN [REVERSE] min_value..max_value LOOP END LOOP; 如: FOR i in [reverse] 1..10 LOOP --statement; END LOOP; */ begin --for循环的不变量不需要事先声明,oracle会自动创建 for i in reverse 1..10 loop dbms_output.put(i||','); end loop; dbms_output.new_line; end; / -- begin --for循环的不变量不需要事先声明,oracle会自动创建 for e in (select * from employee order by empno) loop dbms_output.put_line(e.empno||','||e.ename||','||e.job||','||e.sal); end loop; dbms_output.new_line; end; / /* 53:根据输入部门编号,按以下格式打印各部门人员姓名: 部门名称:RESEARCH 部门人员:SMITH,JONES,FORD 提示:灵活利用子查询和rownum伪列 1. 确定循环的次数:count(*) cnt 2. rownum=(1...cnt) */ declare v_rownum int; v_ename string(20); v_dname string(20); v_deptno department.deptno%type; begin v_deptno := &请输入部门编号:; select dname,count(e.ename) into v_dname,v_rownum from employee e, department d where e.deptno=d.deptno and d.deptno=v_deptno group by dname; dbms_output.put_line('部门名称:'||v_dname); dbms_output.put('员工名称:'); for i in 1..v_rownum loop select ename into v_ename from ( select ename,rownum rn from emp where deptno=v_deptno ) a where a.rn=i; dbms_output.put(v_ename); if i<v_rownum then dbms_output.put(','); end if; end loop; dbms_output.new_line; end; / --方式2 declare v_rownum int := 1; v_ename string(20); v_dname string(20); v_deptno department.deptno%type; begin v_deptno := &请输入部门编号:; select dname into v_dname from department where deptno=v_deptno; --统计行数 select count(ename) into v_rownum from emp where deptno=v_deptno; dbms_output.put_line('部门名称:'||v_dname); dbms_output.put('员工名称:'); --输入本部门中的员工名字 for e in (select ename,rownum rn from emp where deptno=v_deptno) loop dbms_output.put(e.rn||'.'||e.ename); if e.rn<v_rownum then dbms_output.put(','); end if; end loop; dbms_output.new_line; end; / /* (三) 顺序控制结构 a) GOTO 语句,跳转到后面的语句去执行,只能向后跳不能向前跳。 */ --若员工的工资小于资金的3倍,则为员工的工资增加30%。 declare v_empno emp.empno%type; v_ename emp.ename%type; v_sal emp.sal%type; v_comm emp.comm%type; begin v_empno := &请输入员工编号:; select ename,sal,comm into v_ename,v_sal,v_comm from emp where empno=v_empno; dbms_output.put_line(v_ename||' 的工资是:'||v_sal||', 奖金是:'||v_comm); if v_sal<(v_comm*3) then goto updating; --跳转到<<updating>> else goto quit; end if; <<updating>> update emp set sal=sal+sal*0.3 where empno=v_empno; commit; dbms_output.put_line(v_ename||'工资修改成功!工资修改后为:'||(v_sal+v_sal*0.3)); <<quit>> null; --空语句 end; / /* (五) 异常处理 a)Oracle预定义异常 oracle常见预定义异常: 错误号 异常错误信息名称 说明 ---------------------------------------------------------------------- ORA-0001 DUP_VAL_ON_INDEX 试图破坏一个唯一性限制 ORA-0051 TIMEOUT_ON_RESOURCE(少用) 在等待资源时发生超时 ORA-0061 TRANSACTION_BACKED_OUT(少用) 由于发生死锁事务被撤消 ORA-1001 INVALID_CURSOR 试图使用一个未打开的游标 ORA-1012 NOT_LOGGED_ON(少用) 没有连接到ORACLE ORA-1017 LOGIN_DENIED(少用) 无效的用户名/口令 ORA-1403 NO_DATA_FOUND SELECT INTO 没有找到数据 ORA-1422 TOO_MANY_ROWS SELECT INTO 返回多行 ORA-1476 ZERO_DIVIDE 试图被零除 ORA-1722 INVALID_NUMBER 转换一个数字失败 VALUE_ERROR 值错误 INVALID_NUMBER 无效的数字 OTHERS 其它的异常(总是放在异常处理块的最后,就象java中Exception的处理放在最后一样) Oracle内置函数 SQLCODE 和 SQLERRM 是特别用在OTHERS异常处理器中,分别用来返回Oracle的错误代码和错误消息。 OTHERS处理器应该是异常处理块中的最后的异常处理器,因为它是用来捕获除了别的异常处理器处理以外的所有的 Oracle异常,所以在程序的最外层使用一个OTHERS处理器的话,将可以确保所有的错误都会被检测到。如果没有异常被触发, 则SQLCODE返回 0。 Oracle内置函数 SQLCODE 和 SQLERRM 是特别用在OTHERS异常处理器中,分别用来返回Oracle的错误代码和错误消息。 */ -- a)Oracle预定义异常 declare rec_emp emp%rowtype; begin -- select * into rec_emp from emp where empno=333; select * into rec_emp from emp; --异常处理 exception when NO_DATA_FOUND then dbms_output.put_line('员工不存!错误码:'||SQLCODE||',错误信息:'||SQLERRM); when TOO_MANY_ROWS then dbms_output.put_line('查询结果员工数过多!错误码:'||SQLCODE||',错误信息:'||SQLERRM); when others then dbms_output.put_line('未知异常!错误码:'||SQLCODE||',错误信息:'||SQLERRM); end; / /* (五) 异常处理 异常处理的步骤: 1. 声明异常 2. 抛出异常:raise ex 3. 处理异常:exception when ex then ..... a)Oracle预定义异常 b)自定义异常 */ --用户自定义异常 declare --1. 声明自定义的异常 ex_salGreatThan exception; rec_emp emp%rowtype; v_comm emp.comm%type; begin select * into rec_emp from emp where empno=8002; v_comm := &请输入员工的奖金:; if v_comm<=100 or v_comm>=500 then --2.抛出异常 raise ex_salGreatThan; else --更新奖金 null; end if; --3. 处理异常:exception when ex then ..... exception when ex_salGreatThan then dbms_output.put_line('更改的奖金过高,奖金必须在: ¥100~¥500之间!错误码:'||SQLCODE||',错误信息:'||SQLERRM); when others then dbms_output.put_line('未知异常!错误码:'||SQLCODE||',错误信息:'||SQLERRM); end; / /* RAISE_APPLICATION_ERROR 存储过程: (1) 用于创建用户定义的错误信息 (2) 可以在可执行部分和异常处理部分使用 (3) 错误编号必须介于 -20000 和 -20999 之间 (4) 错误消息的长度可长达 2048 个字节 语法: RAISE_APPLICATION_ERROR(error_number, error_message); RAISE_APPLICATION_ERROR是专门有来将数据库程序的错误从数据库服务器端传到客户端应用程序如java程序。 */ declare --1. 声明自定义的异常 ex_salGreatThan exception; rec_emp emp%rowtype; v_comm emp.comm%type; begin select * into rec_emp from emp where empno=8002; v_comm := &请输入员工的奖金:; if v_comm<=100 or v_comm>=500 then --2.抛出异常 raise ex_salGreatThan; else --更新奖金 null; end if; --3. 处理异常:exception when ex then ..... exception when ex_salGreatThan then raise_application_error(-20000,'更改的奖金过高,奖金必须在: ¥100~¥500之间!错误码:'||SQLCODE||',错误信息:'||SQLERRM); when others then raise_application_error(-20999,'未知异常!错误码:'||SQLCODE||',错误信息:'||SQLERRM); end; /
相关文章推荐
- My Sql connector Net 安装及C# 连接My Sql数据库
- Oracle导出DMP文件的两种方法
- 不好的MySQL过程编写习惯
- ERROR 2002 (HY000): Can't Connect to Local MySQL Server Through Socket '/tmp/mysql.sock'
- oracle 函数调用
- PLSQL连接远程Oracle出现ORA-12541: 无监听程序
- ubuntu12.04已安装SQLite3 而简单易用
- Redis 作为缓存服务器的配置
- 如何查看Oracle中同义词的表结构
- mysql引擎
- 修改 oracle xe 默认中文字符集成为:SIMPLIFIED CHINESE_CHINA.ZHS16GBK
- 安装MySQL在最后的start service停住了解决方法
- 09安装运行redis-trib.rb所需的环境
- 08Redis入门指南笔记(集群)
- iOS开发之SQLite3基础
- orcal命令
- [Oracle] 物理结构介绍
- 树形结构的数据库的存储
- 安装了多个Oracle11g的客户端,哪个客户端的tnsnames.ora会起作用?
- [Oracle] 逻辑结构实验与总结