[Oracle] PL/SQL学习笔记
-- 1. 使用一个变量 declare -- Local variables here v_name varchar2(50); begin -- Test statements here select t.user_name into v_name from pay_mer_order t where t.id=3530816; dbms_output.put_line(v_name); end; -- 2. 使用多个变量 declare -- Local variables here v_name varchar2(50); v_trans_no varchar2(50); v_app_code varchar2(50); begin -- Test statements here select t.user_name, t.pay_brh_trans_no, t.app_code into v_name, v_trans_no, v_app_code from pay_mer_order t where t.id=3530816; dbms_output.put_line(v_name || ',' || v_trans_no || ',' || v_app_code); end; --3. 自定义记录类型 declare -- 自定义一个记录类型 type order_info is record( v_name varchar2(50), v_trans_no varchar2(50), v_app_code varchar2(50)); --声明自定义记录类型的变量 v_tmp_record order_info; begin select t.user_name, t.pay_brh_trans_no, t.app_code into v_tmp_record from pay_mer_order t where t.id=3530816; dbms_output.put_line(v_tmp_record.v_name || ',' || v_tmp_record.v_trans_no || ',' || v_tmp_record.v_app_code); end; -- 4. 使用%type定义变量,动态的获取数据的声明类型 declare -- 定义一个记录类型 type order_info is record( v_name pay_mer_order.user_name%type, v_trans_no pay_mer_order.pay_brh_trans_no%type, v_app_code pay_mer_order.app_code%type); --声明自定义记录类型的变量 v_tmp_record order_info; begin select t.user_name, t.pay_brh_trans_no, t.app_code into v_tmp_record from pay_mer_order t where t.id=3530816; dbms_output.put_line(v_tmp_record.v_name || ',' || v_tmp_record.v_trans_no || ',' || v_tmp_record.v_app_code); end; -- 5. 使用%rowtype定义变量,动态的获取数据的声明类型 declare -- 声明一个记录类型的变量 v_tmp_record pay_mer_order%rowtype; begin select t.* into v_tmp_record from pay_mer_order t where t.id=3530816; dbms_output.put_line(v_tmp_record.user_name || ',' || v_tmp_record.pay_brh_trans_no || ',' || v_tmp_record.app_code); end; -- 6. 赋值语句:通过变量实现查询语句 declare -- 声明一个记录类型的变量 v_tmp_record pay_mer_order%rowtype; v_order_info_id pay_mer_order.id%type; begin v_order_info_id := 3530816; select t.* into v_tmp_record from pay_mer_order t where t.id=v_order_info_id; dbms_output.put_line(v_tmp_record.user_name || ',' || v_tmp_record.pay_brh_trans_no || ',' || v_tmp_record.app_code); end; --7. 通过变量实现DELET, INSERT, UPDATE等操作 declare -- 声明一个记录类型的变量 v_order_info_id pay_mer_order.id%type; begin v_order_info_id := 3530816; delete from pay_mer_order t where t.id=v_order_info_id; commit; end; --8. 使用IF... THEN ... ELSIF ...THEN...ELSE...END IF; --要求: 查询出 150 号 员工的工资, 若其工资大于或等于 10000 则打印 'salary >= 10000'; 若在 5000 到 10000 之间, 则打印 '5000<= salary < 10000'; 否则打印 'salary < 5000' --(方法一) declare v_salary employees.salary%type; begin --通过 select ... into ... 语句为变量赋值 select salary into v_salary from employees where employee_id = 150; dbms_output.put_line('salary: ' || v_salary); -- 打印变量的值 if v_salary >= 10000 then dbms_output.put_line('salary >= 10000'); elsif v_salary >= 5000 then dbms_output.put_line('5000 <= salary < 10000'); else dbms_output.put_line('salary < 5000'); end if; --(方法二) declare v_emp_name employees.last_name%type; v_emp_sal employees.salary%type; v_emp_sal_level varchar2(20); begin select last_name,salary into v_emp_name,v_emp_sal from employees where employee_id = 150; if(v_emp_sal >= 10000) then v_emp_sal_level := 'salary >= 10000'; elsif(v_emp_sal >= 5000) then v_emp_sal_level := '5000<= salary < 10000'; else v_emp_sal_level := 'salary < 5000'; end if; dbms_output.put_line(v_emp_name||','||v_emp_sal||','||v_emp_sal); end; --9. 使用 CASE ... WHEN ... THEN ...ELSE ... END 完成上面的任务 declare v_sal employees.salary%type; v_msg varchar2(50); begin select salary into v_sal from employees where employee_id = 150; --case 不能向下面这样用 /* case v_sal when salary >= 10000 then v_msg := '>=10000' when salary >= 5000 then v_msg := '5000<= salary < 10000' else v_msg := 'salary < 5000' end; */ v_msg := case trunc(v_sal / 5000) when 0 then 'salary < 5000' when 1 then '5000<= salary < 10000' else 'salary >= 10000' end; dbms_output.put_line(v_sal ||','||v_msg); end; --10. 使用 CASE ... WHEN ... THEN ... ELSE ... END; --要求: 查询出 122 号员工的 JOB_ID, 若其值为 'IT_PROG', 则打印 'GRADE: A'; 'AC_MGT', 打印 'GRADE B', 'AC_ACCOUNT', 打印 'GRADE C'; 否则打印 'GRADE D' declare --声明变量 v_grade char(1); v_job_id employees.job_id%type; begin select job_id into v_job_id from employees where employee_id = 122; dbms_output.put_line('job_id: ' || v_job_id); --根据 v_job_id 的取值, 利用 case 字句为 v_grade 赋值 v_grade := case v_job_id when 'IT_PROG' then 'A' when 'AC_MGT' then 'B' when 'AC_ACCOUNT' then 'C' else 'D' end; dbms_output.put_line('GRADE: ' || v_grade); end; --11. 使用循环语句打印1-100.(三种方式) --a. LOOP...EXIT WHEN ... END LOOP declare v_i number(3) :=1; begin loop dbms_output.put_line(v_i); exit when v_i = 100; v_i := v_i + 1; end loop; end; --b. WHILE...LOOP...END LOOP declare v_i number(3) := 1; while v_i <= 100 loop dbms_output.put_line(v_i); v_i := v_i + i; end loop; end; --c. FOR...IN...LOOP begin for i in 1..100 loop dbms_oupput_put_line(i); end loop; end; --12. 综合使用if, while语句,打印1-100之间的所有素数 --(素数:有且公有两个正约数的整数,2, 3, 5,7,11,13...) declare v_i number(3) := 2; v_j number(3) := 2; v_flag number(1) := 0; begin while v_i < 101 loop v_j := 2; while v_j < v_i loop if(mod(v_i, v_j) = 0) then v_flag := 1; end if; exit when v_flag = 1; end loop; if(v_flag = 0) then dbms_output.put_line(v_i); end if; v_i := v_i + 1; end loop; end; --13. 使用for in实现12 declare v_flag number(1) := 0; begin for i in 2..100 loop for j in 2...i loop if(mod(i, j) = 0) then v_flag := 1; end if; exit when v_flag = 1; end loop; if(v_flag = 0) then dbms_output.put_line(i); end if; end loop; end; --14. goto declare v_flag number(1) := 0; begin for i in 2..100 loop v_flag := 1; for j in 2..sqrt(i) loop if i mod j = 0 then v_flag := 0; goto label; end if; end loop; <<label>> if v_flag = 1 then dbms_output.put_line(i); end if; end loop; end; ----------------------------------------------------------------------------
--游标的使用 --游标1. 打印出80部门的所有的员工的工资 declare --a. 定义游标 cursor salary_cursor is select salary from employees where department_i = 80; v_salary employees.salary%type; begin --b. 打开游标 open salary_cursor; --c. 提取游标 fetch salary_cursor into v_salary; --d. 对游标进行循环操作:判断游标中是否有下一条记录 while salary_cursor%found loop dbms_output.put_line('salary: ' || v_salary); fetch salary_cursor into v_salary; end loop; --e. 关闭游标 close salary_cursor; end; --游标2. 打印出80部门的所有员工的工资:Xxx's salary is: xxx declare cursor salary_cursor is select e.salary, e.last_name from employees e where department_i = 80; v_sal number(10); v_name varchar2(20); begin open salary_cursor; fetch salray_cursor into v_sal, v_name; while salary_cursor%found loop dbms_output.put_line(v_name || '、s salary is: ' || v_sal); fetch salary_cursor into v_sal, v_name; end loop; close salary_cursor; end; --游标3:打印同manage_id为100的员工的last_name, email, salary信息(使用游标,记录类型) declare type v_emplyee is record( name emplyees.last_name%type, mail emplyees.email%type, sal emplyees.salary%type); v_employee_info v_employee; cursor salary_cursor is select e.last_name, e.email, e.salary from employees e where e.manage_id = 100; begin open salary_cursor; fetch salary_cursor into v_emplyeee_info; while salary_cursor%found loop dbms_output.put_line(v_employee_info.name || '、s salary is: ' || v_employee_info.mail ', email is: ' || v_employee_info.mail); fetch salary_cursor into v_employee_info; end loop; close salary_cursor; end; --游标4:使用for .. in declare type v_emplyee is record( name emplyees.last_name%type, mail emplyees.email%type, sal emplyees.salary%type); v_employee_info v_employee; cursor salary_cursor is select e.last_name, e.email, e.salary from employees e where e.manage_id = 100; begin for v_employee_info in salary_cursor loop dbms_output.put_line(v_employee_info.name || '、s salary is: ' || v_employee_info.mail ', email is: ' || v_employee_info.mail); end loop; end; --游标5:利用游标,调整公司中员工的工资 --0~5000 5%, 5000~10000 3%, 10000~15000 2%, 150~ 1% declare salary_info employees&rowtype cursor salary_adjust_cursor is select e.* from employees v_adjust number(4, 2); begin for salary_info in salary_adjust_cursor loop if(salary_info.salary <= 5000) then v_adjust := 0.05; elsif(salary_info.salary <= 10000) then v_adjust := 0.03; elsif(salary_info.salary <= 15000) then v_adjust := 0.02; else v_adjust := 0.01; end if; update employees e set e.salary=(s.salary + e.salary * v_adjust) where t.id = salary_info.id; end loop; end; --游标6:带参数的游标 declare salary_info employees&rowtype cursor salary_adjust_cursor(dept_id number, sal number) is select salary + 1000 sal, employee_id id from employees e where t.department_id = dept_id and salary > sal; v_adjust number(4, 2); begin for salary_info in salary_adjust_cursor(sal => 4000, dept_id => 80) loop if(salary_info.salary <= 5000) then v_adjust := 0.05; elsif(salary_info.salary <= 10000) then v_adjust := 0.03; elsif(salary_info.salary <= 15000) then v_adjust := 0.02; else v_adjust := 0.01; end if; update employees e set e.salary=(s.salary + e.salary * v_adjust) where t.id = salary_info.id; end loop; end; --游标7:隐式游标,更新指定员工salary涨10%,如果该员工没找到,则打印“查无此人” begin update employees e set salary = salary + salary * 0.1 where e.employees_id = 1055; if sql%notfound then dbms_output.put_line('查无此人!'); end if; end; ----------------------------------------------------------------------------
--异常处理1 declare v_sal employees.salary%type; begin select salary into v_sal from employees e where e.employee_id > 100; dbms_output.put_line(v_sal); exception when Too_many_rows then dbms_output.put_line('输出的行数太多了'); end; --非预定义异常2 declare v_sal employees.salary%type; --声明一个异常 delete_mgr_excep exception; --把自定义的异常和oracle的错误关联起来 PRAGMA EXCEPTION INIT(delete_mgr_excep, -2292); begin delete from employees e where e.employee_id = 100; select salary into v_sal from employees where employee_id > 100; dbms_output.put_line(v_sal); exception when Too_many_rows then dbms_output.put_line('输出的行数太多了'); when delete_mgr_excep then dbms_output.put_line('Manager不能直接被删除'); end; --用户自定义异常3 declare v_sal employees.salary%type; --声明一个异常 delete_mgr_excep exception; --把自定义的异常和oracle的错误关联起来 PRAGMA EXCEPTION INIT(delete_mgr_excep, -2292); --声明一个异常 too_high_sal exception; begin select salary into v_sal from employees where employee_id > 100; dbms_output.put_line(v_sal); if(v_sql > 1000) then raise too_high_sal; end if; exception when Too_many_rows then dbms_output.put_line('输出的行数太多了'); when delete_mgr_excep then dbms_output.put_line('Manager不能直接被删除'); --处理异常 when too_high_sal then dbms_output.put_line('工资过高了'); end; --异常的基本程序4 declare v_sal employees.salary%type; begin select salary into v_sal from employees where employee_id=1000; dbms_output.put_line('salary: ' || v_sal); exception when No_data_found then dbms_output.put_line('未找到数据'); end; ---------------------------------------------------------------------------- --存储过程和函数 --存储函数:有返回值,创建完成后,通过select function() from dual;执行 --存储过程:由于没有返回值,创建完成后,不能使用select语句,只能使用pl/sql块执行 --函数的声明(有参数的写在小括号里) create or replace function func_name(v_param varchar2) --返回值类型 return varchar2 is --PL/SQL块变量、记录类型、游标的声明(类似于前面的declare的部分) begin --函数体(可以实现crud操作,返回值需要return) return 'hello world' || v_param; end; --存储函数1:helloworld create or replace function hello_func return varchar2 is begin return 'hello world'; end; --执行函数 begin dbms_output.put_line(hello_func()); end; --或者 select hello_func() from dual; --存储函数2:参数输入 create or replace function hello_func(v_logo varchar2) return varchar2 is begin return 'hello world ' || v_logo; end; --存储函数3:使用OUT型的参数,因为函数只能有一个返回值,PL/SQL程序可以通过OUT型的参数实现多个返回值 --要求: 定义一个函数: 获取给定部门的工资总和 和 该部门的员工总数(定义为 OUT 类型的参数). --要求: 部门号定义为参数, 工资总额定义为返回值. create or replace function sum_sql(dept_id number, total_count out number) return number is cursor sal_cursor is select salary from employees where department_id = dept_id; v_sum_sal number(8) := 0; begin total_count := 0; for c in sal_cursor loop v_sum_sal := v_sum_sal + c.salary; total_count := total_count + 1; end loop; return v_sum_sal; end; --执行函数 declare v_total number(3) := 0; begin dbms_output.put_line(sum_sal(80, v_total)); dbms_output.put_line(v_total); end; ----------------------------------------------------------------------------
--触发器1:helloworld触发器 create or replace trigger hello_trigger after update on employees begin dbms_output.put_line('hello world..'); end; --在执行以下更新语句之后会打出hello world update employees set salary = salary + 1000; --触发嚣2:行触发器 create or replace trigger employees_trigger after update on employees for each row begin dbms_output.put_line('修改了一条记录'); end; --触发嚣2:语句级触发器:一个update/delete/insert语句只使触发器执行一次 create or replace trigger employees_trigger after update on employees begin dbms_output.put_line('修改了一条记录'); end; --触发嚣3:使用:new, :old修饰符 create or replace trigger employees_trigger after update on employees for each row begin dbms_output.put_line('old salary: ' || :old.salary || ', new salary: ' || :new.salary); end;
路慢慢其休远羲,吾将上下而求所