一、plsql编程
oracle中所拥有的一种编程语言,功能强大
二、存储过程procedure
1.创建存储过程语法
CREATE [OR REPLACE] PROCEDURE pname
[ (paramName1 [mode1] type1,
param2 [mode2] type2,
…)]
ename in varchar2,
job out varchar2,
sal in out number
IS | AS
[变量定义声明部分,如:
变量1 INTEGER :=0;
变量2 DATE;
]
BEGIN
PL/SQL Block
END [pname]
–pname:过程名称
–param1、param2:形参名称
–mode1、mode2:参数模式,
IN (默认)表示输入参数,按值传递方式。
OUT 表示输出参数,可以理解为按引用传递方式。可以作为存储过程的输出结果,供外部调用者使用。
IN OUT 即可作输入参数,也可作输出参数。
–type1、type2:参数数据类型
参数的数据类型只需要指明类型名即可,不需要指定宽度。
参数的宽度由外部调用者决定。
过程可以有参数,也可以没有参数
–变量声明块:
紧跟着的as (is )关键字,可以理解为pl/sql的declare关键字,用于声明变量。
变量声明块用于声明该存储过程需要用到的变量,它的作用域为该存储过程。另外这里声明的变量必须指定宽度。
遵循PL/SQL的变量声明规范。
–PL/SQL Block:过程语句块 从begin 关键字开始为过程的语句块。存储过程的具体逻辑在这里来实现。:由end 关键字结束。
2.SELECT INTO STATEMENT
将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判断
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循环
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.变量赋值
V_TEST := 123;
6.例1,功能需求:
要给指定的(通过雇员编号指定)雇员加薪,如果雇员编号在200以内加薪10%,雇员编号大于等于200则加薪15%,创建存储过程的SQL语句如下(HR用户)
CREATE OR REPLACE PROCEDURE raise_salary //raise_salary存储过程的名字
(p_id IN employees.employee_id%TYPE) //p_id存储过程的参数 in从外部传入 ,指定的类型是 //employees这个表中的employee_id的一样的类型
AS
BEGIN
IF p_id >= 200 THEN
BEGIN
UPDATE employees
SET salary = salary * 1.15
WHERE employee_id = p_id;
END;
END IF;
IF p_id < 200 THEN
BEGIN
UPDATE employees
SET salary = salary * 1.10
WHERE employee_id = p_id;
END;
END IF;
END [raise_salary]?
调用存储过程
–在SQL*PLUS中被调用的语句为
?EXECUTE raise_salary(207)
?或EXEC raise_salary(207)
–而在PL/SQL代码中则直接使用
begin
?raise_salary(207)
end
例2 创建存储过程
create or replace procedure p1
(v_a in number,v_b number,v_ret out number,v_temp in out number)
is
declare
v_a number;
v_b number;
v_ret number;
v_temp number:=5;
begin
if (v_a>v_b) then
v_ret:=v_a;
else
v_ret:=v_b;
end if;
v_temp:=v_temp+1;
end;
调用存储过程
declare
v_a number;
v_b number;
v_ret number;
v_temp number:=5;
begin
p1(&v_a的值,&v_b的值,v_ret,v_temp);
dbms_output.put_line(v_ret);
dbms_output.put_line(v_temp);
end;
jdbc调用存储过程:
create or replace procedure emp_sal(eno emp.empno%type,esal out emp.sal%type)
as
begin
select sal into esal from emp where empno=eno;
end;
三、函数function
1.函数和存储过程的区别
2.函数创建
–CREATE [OR REPLACE] FUNCTION fname
[ (param1 [mode1] type1,
param2 [mode2] type2,
…)]
RETURN type
IS | AS
BEGIN
PL/SQL Block
END [fname]
–其中必须注意的是在IS | AS之前要确定返回值类型,在PL/SQL Block块中需要有效的返回语句
3.例:
–假设要创建一个通过员工编号获取部门经理编号的函数,其SQL语句如下(HR用户)
?CREATE OR REPLACE FUNCTION get_manager_id
(p_id IN employees.employee_id%TYPE)
RETURN NUMBER
IS
v_manager_id employees.manager_id%TYPE :=0;
BEGIN
SELECT manager_id INTO v_manager_id
FROM employees WHERE employee_id = p_id;
RETURN v_manager_id;
END get_manager_id;
4.调用函数
不能单独执行函数,只能作为表达式的一部分。
SELECT get_manager_id(207) FROM dual
四、游标cursor(了解)
1.游标的概念
查询的结果集
2.游标优缺点
优点:可以对结果进行方便的操作,适合用小数据量
缺点:不适合大数据量操作,数据量大的时候操作慢,耗占内存和cpu(资源)
由于缺点较明显不建议在真正的项目中使用
3.游标的分类
(1)显式游标
DECLARE
my_toy_price toys.toyprice%TYPE;
CURSOR toy_cur IS SELECT toyprice FROM toys
WHERE toyprice<250;//1.定义游标
BEGIN
OPEN toy_cur; //2.打开游标
LOOP //循环,3.循环使用游标
FETCH toy_cur INTO my_toy_price; //从游标中取出值赋值给my_toy_price
EXIT WHEN toy_cur%NOTFOUND; //当游标中已经没有发现值
DBMS_OUTPUT.PUT_LINE
(‘TOYPRICE=:玩具单价=:‘||my_toy_price);
END LOOP;
CLOSE toy_cur;//4.关闭游标
END;
--显式游标的定义和使用(使用loop循环)
declare
ename emp.ename%type;
esal emp.sal%type;
cursor nscur is select ename,sal from emp;--定义游标
begin
open nscur;--打开游标
loop
fetch nscur into ename,esal;--遍历游标,从游标中获取值赋给2个变量
exit when nscur%NOTFOUND; --当游标遍历完成后退出循环
dbms_output.put_line(‘姓名:‘||ename||‘ 薪资:‘||esal);
end loop;
close nscur;--关闭游标
end;
--显式游标的定义和使用(使用for循环)
declare
ename1 emp.ename%type;
esal emp.sal%type;
cursor nscur is select ename,sal from emp;--定义游标
begin
--open nscur;--打开游标
for ename1 in nscur loop
dbms_output.put_line(ename1.ename||ename1.sal);
end loop;
-- close nscur;--关闭游标
end;
缺点:比较麻烦,步骤繁琐
优点:可以操作(修改、删除)结果集(游标)的内容
(2)隐式游标
select cname into courseName from course
?隐式游标的属性有:
–%FOUND – SQL 语句影响了一行或多行时为 TRUE
–%NOTFOUND – SQL 语句没有影响任何行时为TRUE
–%ROWCOUNT – SQL 语句影响的行数
–%ISOPEN - 游标是否打开,始终为FALSE
BEGIN
UPDATE toys SET toyprice=27 WHERE toyid= ‘P005‘;
//使用了隐式游标,当上面的update语句影响行数>=1,返回true,否则返回false
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE(‘表已更新‘);
END IF;
END;
五、触发器trigger
1、触发器的概念
数据库一个对象,是由数据库自动管理的,不需要人为去调用
触发器涉及的概念:
?当设置为Statement(默认)时,称为语句触发器,触发器体对于触发事件只执行一次,即使没有行受影响;当设置为Row时,称为行触发器,触发器体对受触发事件影响的每行执行一次
作用:
(1)自动生成数据
(2)自定义复杂的安全权限
(3)提供审计和日志记录
(4)启用复杂的业务逻辑
分类:
2、触发器的创建
(1)语句触发器(默认statement)
–CREATE [OR REPLACE] Trigger tname
timing(AFTER | BEFORE)
event1 [OR event2 OR event3] (INSERT/UPDATE/DELETE)
ON table
trigger_body
?tname表示触发器名字
?timing表示触发时间
?event1、event2和event3表示触发事件
?table表示针对的表,trigger_body表示触发器体(PLSQL表示做什么事)
(2)行触发器(row)
–CREATE [OR REPLACE] Trigger tname
timing
event1 [OR event2 OR event3]
ON table
[REFERENCING OLD AS old | NEW AS new]
FOR EACH ROW
[WHEN(condition)]
trigger_body
?触发器中增加的REFERENCING OLD AS old | NEW AS new表示声明当前行新、老值的别名,默认别名是old和new
?FOR EACH ROW表示此触发器为行触发器
?WHEN(condition)表示触发器的约束
3.例子
(1)语句触发器
–只能在周一到周五的9:00到18:00才可以针对部门表departments进行DML操作
CREATE OR REPLACE TRIGGER dml_depts_time
BEFORE
INSERT OR UPDATE OR DELETE
ON departments
BEGIN
IF TO_CHAR(SYSDATE, ‘HH24:MI‘) NOT BETWEEN ‘08:00‘ AND ‘18:00‘ OR TO_CHAR (SYSDATE, ‘DY‘) IN (‘SAT‘, ‘SUN‘) THEN
RAISE_APPLICATION_ERROR (-20205,‘You may only make changes during normal office hours‘);
END IF;
END dml_depts_time;
测试:?UPDATE departments
SET department_name = ‘IT GROUP‘
WHERE department_id = 60
(2)行触发器
当更改了雇员表中某行的职位编号字段或部门编号字段,自动在职位变迁表job_history中增加一行记录,记录该雇员的职位(包括部门)变迁情况
?CREATE OR REPLACE TRIGGER update_job_history
AFTER
UPDATE OF job_id, department_id
ON employees
FOR EACH ROW
BEGIN
INSERT INTO job_history (employee_id, start_date, end_date, job_id, department_id)
VALUES(:old.employee_id, :old.hire_date, sysdate, :old.job_id, :old.department_id);
END;
测试:
?UPDATE employees
SET department_id = 90
练习:创建一个日志表记录对course表的操作
第一步、创建日志表
第二步创建触发器
第三步测试触发器
原文地址:https://www.cnblogs.com/hglibin/p/9907818.html