oracle复习笔记之PL/SQL程序所要了解的知识点
PL/SQL的基本语法、记录类型、流程控制、游标的使用、
异常处理机制、存储函数/存储过程、触发器。
为了要有输出的结果,在写PL/SQL程序前都在先运行这一句:
结构:
--声明变量、类型、游标
--程序的执行部分(类似于java里的main()方法)
--针对begin块中出现的异常,提供处理的机制
--when...then...
--when...then...
举例1:
declare v_salnumber(10);(注意每句话后面别忘记了分号,跟java中的一样) begin selectsalaryintov_salfromemployeeswhereemployee_id=100; dbms_output.put_line(v_sal); end;
举例2:
declare v_salnumber(10);(注意,这里声明的空间大小不能比原表中的小) v_emailvarchar2(20); v_hire_datedate; begin selectsalary,email,hire_dateintov_sal,v_email,v_hire_datefromemployeeswhereemployee_id= 100; dbms_output.put_line(v_sal||","||v_email||","||v_hire_date); end; 或者: declare v_salemployees.salary%type; v_emailemployees.email%type; v_hire_dateemployees.hire_date%type; begin selectsalary,email,hire_dateintov_sal,v_email,v_hire_datefromemployeeswhereemployee_id= 100; dbms_output.put_line(v_sal||","||v_email||","||v_hire_date); end;
declare typeemp_recordisrecord( v_salemployees.salary%type, v_emailemployees.email%type, v_hire_dateemployees.hire_date%type ); v_emp_recordemp_record; begin selectsalary,email,hire_dateintov_emp_recordfromemployeeswhereemployee_id=100; dbms_output.put_line(v_emp_record.v_sal||","||v_emp_record.v_email||","|| v_emp_record.v_hire_date); end;
1、pl/sql基本的语法格式
2、记录类型
3、流程控制:
3.1条件判断(两种)
方式一:
方式二:
3.2循环结构(三种)
方式一:
方式二:
方式三:
3.3goto、exit
4.游标的使用(类似于java中的Iterator)
5.异常的处理
6.会写一个存储函数(
7.会写一个触发器
复习记录类型:
declare typeemp_recordisrecord( --v_emp_idemployees.employee_id%type, --v_salemployees.salary%type v_emp_idnumber(10):=120, v_salnumber(10,2):=12000 ); v_emp_recordemp_record; begin --selectemployee_id,salaryintov_emp_recordfromemployeeswhereemployee_id=123; dbms_output.put_line("employee_id:"||v_emp_record.v_emp_id||""||"salary:"|| v_emp_record.v_sal); end;
也可以升级一下,要是想对表的所有列都输出,则:(须注意输出的列名要跟表中的列名要一样)
declare v_emp_recordemployees%rowtype; begin select*intov_emp_recordfromemployeeswhereemployee_id=123; dbms_output.put_line("employee_id:"||v_emp_record.employee_id||""||"salary:"|| v_emp_record.salary); end; 使用记录来执行update操作: declare v_emp_idnumber(10); begin v_emp_id:=123; updateemployees setsalary=salary+100 whereemployee_id=v_emp_id; dbms_output.put_line("执行成功!~~"); end;
查询150号员工的工资,若其工资大于或等于10000则打印‘salary>=10000";
若在5000到10000之间,则打印‘5000<=salary<10000";否则打印‘salary<5000"
declare v_salemployees.salary%type; begin selectsalaryintov_salfromemployeeswhereemployee_id=150; ifv_sal>=10000thendbms_output.put_line("salary>=10000"); elsifv_sal>5000thendbms_output.put_line("10000>salary>=5000"); elsedbms_output.put_line("salary<5000"); endif; dbms_output.put_line("salary:"||v_sal); end; 利用case...when...then...when...then...else...end实现上题; declare v_salemployees.salary%type; v_tempvarchar2(20); begin selectsalaryintov_salfromemployeeswhereemployee_id=150; v_temp:= casetrunc(v_sal/5000)when0then"salary<5000" when1then"5000<=salary<10000" else"salary>=10000" end; dbms_output.put_line("salary:"||v_sal||""||v_temp); end;
查询出122号员工的job_id,若其值为‘IT_PROG",则打印‘GRADE:A"
‘AC_MGT",则打印‘GRADE:B"
‘AC_ACCOUNT",则打印‘GRADE:B"
否则打印‘GRADE:D"
declare v_job_idemployees.job_id%type; v_tempvarchar2(20); begin selectjob_idintov_job_idfromemployeeswhereemployee_id=122; v_temp:= casev_job_idwhen"IT_PROG"then"A" when"AC_MGT"then"B" when"AC_ACCOUNT"then"C" else"D" end; dbms_output.put_line("job_id:"||v_job_id||""||v_temp); end;
使用循环语句打印:1-100
declare v_inumber(5):=1; begin loop dbms_output.put_line(v_i); exitwhenv_i>=100; v_i:=v_i+1; endloop; end; 使用while实现: declare v_inumber(5):=1; begin whilev_i<=100loop dbms_output.put_line(v_i); v_i:=v_i+1; endloop; end; 使用for...in...loop...endloop;实现: begin forcin1..100loop dbms_output.put_line(c); endloop; end;
declare v_inumber(3):=2; v_jnumber(3):=2; v_flagnumber(1):=1; begin whilev_i<=100loop whilev_j<=sqrt(v_i)loop ifmod(v_i,v_j)=0thenv_flag:=0; endif; v_j:=v_j+1; endloop; ifv_flag=1thendbms_output.put_line(v_i); endif; v_j:=2; v_i:=v_i+1; v_flag:=1; endloop; end;
利用for循环实现输出2-100之间的质数:
declare v_flagnumber(1):=1; begin forv_iin2..100loop forv_jin2..sqrt(v_i)loop ifmod(v_i,v_j)=0thenv_flag:=0; endif; endloop; ifv_flag=1thendbms_output.put_line(v_i); endif; v_flag:=1; endloop; end;
可以用goto改进一下:
declare v_flagnumber(1):=1; begin forv_iin2..100loop forv_jin2..sqrt(v_i)loop ifmod(v_i,v_j)=0thenv_flag:=0; gotolabel; endif; endloop; <<label>> ifv_flag=1thendbms_output.put_line(v_i); endif; v_flag:=1; endloop; end;
打印1-100的自然数,当打印到50时,跳出循环,输出‘打印结束":
begin foriin1..100loop ifi=50thengotolabel; endif; dbms_output.put_line(i); endloop; <<label>> dbms_output.put_line("打印结束"); end; 或者: begin foriin1..100loop ifi=50thendbms_output.put_line("打印结束"); exit; endif; dbms_output.put_line(i); endloop; end;
打印出80部门的所有的员工的工资:salary:XXX
declare
v_salemployees.salary%type;
begin
whileemp_sal_cursor%foundloop
dbms_output.put_line("salary:"||v_sal);
fetchemp_sal_cursorintov_sal;
endloop;
end;
可以进行优化如下:
declare v_empidemployees.employee_id%type; v_lastNameemployees.last_name%type; v_salemployees.salary%type; cursoremp_sal_cursorisselectemployee_id,last_name,salaryfromemployeeswhere department_id=80; begin openemp_sal_cursor; fetchemp_sal_cursorintov_empid,v_lastName,v_sal; whileemp_sal_cursor%foundloop dbms_output.put_line("employee_id:"||v_empid||","||"last_name:"||v_lastName||", "||"salary:"||v_sal); fetchemp_sal_cursorintov_empid,v_lastName,v_sal; endloop; closeemp_sal_cursor; end;
或者使用记录再优化一下:
declare typeemp_recordisrecord( v_empidemployees.employee_id%type, v_lastNameemployees.last_name%type, v_salemployees.salary%type ); v_emp_recordemp_record; cursoremp_sal_cursorisselectemployee_id,last_name,salaryfromemployeeswhere department_id=80; begin openemp_sal_cursor; fetchemp_sal_cursorintov_emp_record; whileemp_sal_cursor%foundloop dbms_output.put_line("employee_id:"||v_emp_record.v_empid||","||"last_name:"|| v_emp_record.v_lastName||","||"salary:"||v_emp_record.v_sal); fetchemp_sal_cursorintov_emp_record; endloop; closeemp_sal_cursor; end;
可以使用for循环最优化:(
declare cursoremp_sal_cursorisselectemployee_id,last_name,salaryfromemployeeswhere department_id=80; begin forcinemp_sal_cursorloop dbms_output.put_line("employee_id:"||c.employee_id||","||"last_name:"||c.last_name||", "||"salary:"||c.salary); endloop; end;
利用游标,调整公司中员工的工资:
工资范围 调整基数
0-5000 5%
5000-10000 3%
10000-15000 2%
15000- 1%
declare cursoremp_cursorisselectemployee_id,salaryfromemployees; v_empidemployees.employee_id%type; v_salemployees.salary%type; v_tempnumber(4,2); begin openemp_cursor; fetchemp_cursorintov_empid,v_sal; whileemp_cursor%foundloop ifv_sal<5000thenv_temp:=0.05; elsifv_sal<10000thenv_temp:=0.03; elsifv_sal<15000thenv_temp:=0.02; elsev_temp:=0.01; endif; dbms_output.put_line(v_empid||","||v_sal); updateemployees setsalary=salary*(1+v_temp) whereemployee_id=v_empid; fetchemp_cursorintov_empid,v_sal; endloop; closeemp_cursor; end;
用for循环实现
declare cursoremp_cursorisselectemployee_id,salaryfromemployees; v_tempnumber(4,2); begin forcinemp_cursorloop ifc.salary<5000thenv_temp:=0.05; elsifc.salary<10000thenv_temp:=0.03; elsifc.salary<15000thenv_temp:=0.02; elsev_temp:=0.01; endif; updateemployees setsalary=salary*(1+v_temp) whereemployee_id=c.employee_id; endloop; end;
begin updateemployees setsalary=salary+10 whereemployee_id=1001; ifsql%notfoundthendbms_output.put_line("查无此人"); endif; end;
declare v_salemployees.salary%type; begin selectsalaryintov_salfromemployees whereemployee_id>100; dbms_output.put_line(v_sal); exception whentoo_many_rowsthendbms_output.put_line("输出的行数过多"); whenothersthendbms_output.put_line("出现其它的异常了"); end;
declare e_deleteid_exceptionexception; pragmaexception_init(e_deleteid_exception,-2292); begin deletefromemployees whereemployee_id=100; exception whene_deleteid_exceptionthendbms_output.put_line("违反了完整性约束,故不能删除此用户"); whenothersthendbms_output.put_line("出现其它的异常了"); end;
declare e_sal_hightexception; v_salemployees.salary%type; begin selectsalaryintov_salfromemployeeswhereemployee_id=100; ifv_sal>10000thenraisee_sal_hight; endif; exception whene_sal_hightthendbms_output.put_line("工资太高了"); whenothersthendbms_output.put_line("出现其它的异常了"); end;
通过select...into...查询某人的工资,若没找到则打印出“未找到此数据”:
declare v_salemployees.salary%type; begin selectsalaryintov_salfromemployeeswhereemployee_id=1001; exception whenno_data_foundthendbms_output.put_line("未找到此数据"); whenothersthendbms_output.put_line("出现其它的异常了"); end; 更新指定员工工资,如工资小于300,则加100,对NO_DATA_FOUND异常,TOO_MANY_ROWS进行处理。 declare v_salemployees.salary%type; begin selectsalaryintov_salfromemployeeswhereemployee_id=1001; ifv_sal<300thenupdateemployeessetsalary=salary+100whereemployee_id=101; endif; exception whenno_data_foundthendbms_output.put_line("未找到此数据"); whentoo_many_rowsthendbms_output.put_line("输出的行数太多了"); whenothersthendbms_output.put_line("出现其它的异常了"); end;
更新指定员工工资,增加100;若指定员工不在,则抛出异常:NO_RESULT;
declare no_resultexception; begin updateemployeessetsalary=salary+100whereemployee_id=1001; ifsql%notfoundthenraiseno_result; endif; exception whenno_resultthendbms_output.put_line("查无此数据,更新失败"); whenothersthendbms_output.put_line("出现其它异常"); end;
写个简单的hello_world存储函数
createorreplacefunctionhello_world returnvarchar2 is(相当于declare,可以在其后面定义变量、记录、游标) begin return"helloworld"; end; 存储函数的调用: begin dbms_output.put_line(hello_world); end; 或者: selecthello_worldfromdual;
createorreplacefunctionhello_world1(v_logovarchar2) returnvarchar2 is begin return"helloworld"||v_logo; end; 调用: selecthello_world1("shellway")fromdual 或者: begin dbms_output.put_line(hello_world1("shellway")); end;
定义一个获取系统时间的函数:
createorreplacefunctionget_sysdate returnvarchar2 is begin returnto_char(sysdate,"yyyy-MM-ddHH24:mi:ss"); end;
createorreplacefunctionadd_param(v_num1number,v_num2number) returnnumber is v_num3number(10); begin v_num3:=v_num1+v_num2; returnv_num3; end; 调用: selectadd_param(2,5)fromdual; 或者: begin dbms_output.put_line(add_param(5,4)); end;
定义一个函数:获取给定部门的工资总和,要求:部门号定义为参数,工资总额为返回值:
createorreplacefunctionget_sal(dept_idnumber) returnnumber is v_sumsalnumber(10):=0; cursorsalary_cursorisselectsalaryfromemployeeswheredepartment_id=dept_id; begin forcinsalary_cursorloop v_sumsal:=v_sumsal+c.salary; endloop; returnv_sumsal; end; 调用: selectget_sal(80)fromdual;
要求:部门号定义为参数,工资总额定义为返回值。
createorreplacefunctionget_sal(dept_idnumber,total_countoutnumber) returnnumber is v_sumsalnumber(10):=0; cursorsalary_cursorisselectsalaryfromemployeeswheredepartment_id=dept_id; begin total_count:=0; forcinsalary_cursorloop v_sumsal:=v_sumsal+c.salary; total_count:=total_count+1; endloop; returnv_sumsal; end; 调用: declare v_countnumber(4); begin dbms_output.put_line(get_sal(80,v_count)); dbms_output.put_line(v_count); end;
(注意:存储过程和存储函数是不一样的,存储函数有返回值而存储过程没有,调用时候存储过程直接调用)
createorreplaceprocedureget_sal1(dept_idnumber,sumsaloutnumber) is cursorsalary_cursorisselectsalaryfromemployeeswheredepartment_id=dept_id; begin sumsal:=0; forcinsalary_cursorloop sumsal:=sumsal+c.salary; endloop; dbms_output.put_line(sumsal); end; 调用: declare v_salnumber(10):=0; begin get_sal1(80,v_sal); end;
对给定部门(作为输入参数)的员工进行加薪操作,若其到公司的时间在(?,95)期间,为其加薪5%
(95,98) 3%
(98,?) 1%
得到以下返回结果:为此次加薪公司每月额外付出多少成三(定义一个OUT型的输出参数)
createorreplaceprocedureadd_sal(dept_idnumber,tempoutnumber) is cursorsal_cursorisselectemployee_id,salary,hire_date fromemployeeswheredepartment_id=dept_id; v_tempnumber(4,2):=0; begin temp:=0; forcinsal_cursorloop ifto_char(c.hire_date,"yyyy")<"1995"thenv_temp:=0.05; elsifto_char(c.hire_date,"yyyy")<"1998"thenv_temp:=0.03; elsev_temp:=0.01; endif; updateemployees setsalary=salary*(1+v_temp) whereemployee_id=c.employee_id; temp:=temp+c.salary*v_temp; endloop; dbms_output.put_line(temp); end; 调用: declare v_inumber(10):=0; begin add_sal(80,v_i); end;
写一个简单的触发器:
createorreplacetriggerupdate_emp_trigger after updateonemployees foreachrow(行级触发器,即每更新一条记录就会输出一次"helloworld",若没有这语句则是语句级触发器) begin dbms_output.put_line("helloworld"); end;
1、 createtableemp1 as selectemployee_id,salary,emailfromemployeeswheredepartment_id=80; 2、 createorreplacetriggerupdate_emp_trigger2 after updateonemp1 foreachrow begin dbms_output.put_line("oldsalary:"||:old.salary||"newsalary:"||:new.salary); end; 3、 updateemp1setsalary=salary+100;
编写一个触发器,在对
1、创建my_emp表: createtablemy_emp as selectemployee_id,salaryfromemployees; 2、创建my_emp_bak表: createtablemy_emp_bak as selectemployee_id,salaryfromemployeeswhere1=2; 3、检查创建的表中的记录: select*frommy_emp select*frommy_emp_bak 4、创建一个触发器: createorreplacetriggerdelete_emp_trigger before deleteonmy_emp foreachrow begin insertintomy_emp_bak values(:old.employee_id,:old.salary); end; 5、执行含有触发器时间的语句: deletefrommy_emp 6、检查触发器执行后的结果: select*frommy_emp select*frommy_emp_bak
相关文章
- Oracle如何导入SQL文件(oracle导入sql文件)
- 优化Oracle SQL优化:提升性能的先进方法(oracle当前sql)
- 管理Oracle 数据库中的分区结构(oracle分区管理)
- Oracle摆脱逗号的突破口(oracle去掉逗号)
- 拼接Oracle表的新姿势(oracle表拼接)
- Oracle数据库中查询日期字段的技巧(oracle查询日期字段)
- Oracle 中优化SQL性能的终极指南(oracle中sql优化)
- 灵活运用Oracle触发器类型实现任务自动化(oracle触发器类型)
- 利用Oracle触发器实现数据库行为自动化(oracle触发器类型)
- 处理Oracle批量SQL处理:加快数据处理速度(oracle批量sql)
- 解密Oracle数据变化监控技巧:保障数据安全与完整性(oracle监控数据变化)
- Oracle表格导出:使用SQL语句快速实现(oracle导出表sql)
- Oracle表空间管理及相关命令(oracle表空间命令)
- 轻松学会:Oracle SQL 格式化技巧(oracle格式化sql)
- Oracle 与 sql 文件相联结(.sql文件oracle)
- Oracle 启动级别的多样性(oracle几个启动级别)
- 成功将1千w数据导入Oracle数据库(1千w数据入oracle)
- 查询从 Oracle 数据库查询记录按时间倒序(oracle 以时间倒叙)
- 实战Oracle SQL实战之旅学以致用(oracle中sql案例)
- Oracle跨越多种数据库的优势(oracle 不同数据库)
- Oracle SQL突破技巧将一行转换为一列 (oracle 一行变一列)
- 解决Oracle SQL遭遇锁死的思路(oracle sql锁死)
- 使用Oracle EMP表练习SQL编程(oracle emp示例)
- Oracle数据库技术及27090问题分析(oracle 27090)