一.pl/sql(Procedure Language/SQL)编程语言
1.概念
PL/SQL是Oracle数据库对SQL语句的扩展。在普通SQL语句的使用上增加了编程语言的特点,所以PL/SQL把数据操作和查询语句组织在PL/SQL代码的过程性单元中,通过逻辑判断、循环等操作实现复杂的功能或者计算。PL/SQL 只有 Oracle 数据库有。 MySQL 目前不支持 PL/SQL 的。
2.变量和常量
声明普通变量:
v_name varchar2(30) := 'tom'; (:=为赋值符号;=为比较符号,相当于java中的==);
声明引用型变量:
v_sal emp.sal%type := 100; 声明的v_sal变量与emp表中sal字段的类型一致;
声明记录型变量:
v_row emp%rowtype; 记录型变量相当于java中的resultset,用来存储整张表中的数据;
声明常量:
v_gender constant number(1) number(1) := 1;
3.分支语句
语法一:if ---then---end if;
语法二:if ---then---else---end if;
语法三:if ---then---elsif---then----else----end if;
举例:
--年龄小于18,显示未成年人,18-60,显示成年人,60以上显示老年人
declare
v_age number(8) :=#
begin
if v_age < 18 then
dbms_output.put_line('未成年人');
elsif v_age >= 18 and v_age <= 60 then
dbms_output.put_line('成年人');
else
dbms_output.put_line('老年人');
end if;
end;
4.循环语句
语法一:loop---exit when----end loop;
举例:
--输出1--100的数
declare
v_num number(8) := 1;
begin
loop
exit when v_num > 100;
dbms_output.put_line(v_num);
v_num := v_num + 1;
end loop;
end;
语法二:while---loop----end loop;
declare
v_num number(8) := 1;
begin
while v_num <= 100 loop
dbms_output.put_line(v_num);
v_num := v_num + 1;
end loop;
end;
语法三:for---in 起始值..终止值---loop---end loop;
declare
v_num number(8) := 1;
begin
for v_num in 1 .. 100 loop
dbms_output.put_line(v_num);
end loop;
end;
5.游标(cursor)
作用:用来接收多条数据结果,相当于java中的ResultSet
语法:cursor 游标名称 is sql 查询语句;
使用:
open 游标名称
loop
fetch 游标名称 into 记录型变理
exit when 游标名称%notfound;
逻辑处理
end loop;
close 游标名称;
举例:
--打印emp表的所有信息
DECLARE
CURSOR c_emp IS SELECT * FROM emp;
v_row emp%ROWTYPE;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO v_row;
EXIT WHEN c_emp%NOTFOUND;
dbms_output.put_line(v_row.ename||'--'||v_row.job);
END LOOP;
CLOSE c_emp;
END;
--带参数的游标
DECLARE
CURSOR c_emp(v_no1 NUMBER, v_no2 NUMBER) IS SELECT * FROM emp WHERE deptno = v_no1 OR deptno = v_no2;
v_row emp%ROWTYPE;
BEGIN
OPEN c_emp(10,20);--传入部门编号deptno
LOOP
FETCH c_emp INTO v_row;
EXIT WHEN c_emp%NOTFOUND;
dbms_output.put_line(v_row.ename||'=='||v_row.job);
END LOOP;
CLOSE c_emp;
END;
6.异常
exception---when----then
--预定义异常
DECLARE
v_num NUMBER(3);
BEGIN
v_num := 10000;
EXCEPTION
WHEN value_error THEN
v_num := 999;
dbms_output.put_line(v_num);
END;
--自定义异常
DECLARE
V_AGE NUMBER(8) := &NUM;
EXC_AGE EXCEPTION; --声明异常
BEGIN
IF V_AGE > 150 THEN
RAISE EXC_AGE;
END IF;
EXCEPTION
WHEN EXC_AGE THEN
RAISE_APPLICATION_ERROR(-20001, 'illegal age');
END;
二.存储过程
概念:一段被命名的plsql,预编译到了数据库中
语法:
create or replace procedure 存储过程名字(参数1 [in]/out 数据类型)
as | is
begin
end;
例子1:
--存储过程,打印指定员工的年薪
create or replace procedure pro_emp_sal(v_no number) is
v_sal number(8, 2);
begin
select sal * 12 + nvl(comm, 0) into v_sal from emp where empno = v_no;
dbms_output.put_line(v_sal);
end;
--方法一调用存储过程
call pro_emp_sal(7788);
--方法二调用存储过程
begin
pro_emp_sal(7788);
end;
例子2:带out参数的存储过程
CREATE OR REPLACE PROCEDURE pro_emp_sal2(v_no NUMBER, v_yearsal OUT NUMBER) IS
BEGIN
SELECT sal*12 + NVL(comm,0) INTO v_yearsal FROM emp WHERE empno = v_no;
END;
--只能使用方式二调用
DECLARE
v_sal NUMBER(8,2);
BEGIN
pro_emp_sal2(7788,v_sal);
dbms_output.put_line(v_sal);
END;
三.存储函数
--存储函数
CREATE OR REPLACE FUNCTION fun_emp_sal(v_no NUMBER)
RETURN NUMBER
IS
v_sal NUMBER(8,2);
BEGIN
SELECT sal*12+NVL(comm,0) INTO v_sal FROM emp WHERE empno = v_no;
RETURN v_sal;
END;
--使用存储函数
BEGIN
dbms_output.put_line(fun_emp_sal(7788));
END;
注:存储过程和存储函数的区别
1、语法不同
2、使用场景:一般存储函数多被存储过程使用,存储过程一般使用在项目和项目之间的数据交互
3、存储函数可以直接在sql中使用,而存储过程不能
select ename,sal,func_emp_sal(empno) from emp;
四.使用jdbc调用存储过程和存储函数
1.BaseDao用于加载驱动和获取连接
2.ProcedureDao用于调用存储过程
3.TestDao用于测试
举例:
1.BaseDao用于加载驱动和获取连接
public class BaseDao {
//加载驱动
static{
try {
Class.forName("oracle.jdbc.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConn() throws SQLException{
String url="jdbc:oracle:thin:@192.168.92.8:1521:orcl";
String user="qin";
String password="qin";
return DriverManager.getConnection(url, user, password);
}
public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.ProcedureDao用于调用存储过程
public class ProcedureDao {
public static Long getSal(Long v_no){
Connection conn = null;
CallableStatement stmt=null;
Long yearsal=0l;
try {
conn=BaseDao.getConn();
stmt = conn.prepareCall("call pro_emp_sal2(?,?)");//调用存储过程
stmt.setLong(1, v_no);
stmt.registerOutParameter(2, OracleTypes.NUMBER); //指定参数的数据类型
stmt.execute();
yearsal = stmt.getLong(2);
} catch (SQLException e) {
e.printStackTrace();
}
return yearsal;
}
}
3.TestDao用于测试
public class TestDao {
public static void main(String[] args) {
CursorDao.getEmp(10l);
}
}
五.触发器
1.--创建添加数据引发操作的触发器
CREATE OR REPLACE TRIGGER tri_add_emp
AFTER
INSERT ON emp
BEGIN
dbms_output.put_line('增加了一条数据');
END;
--增加一条数据,看是否会触发
INSERT INTO emp(empno,ename,deptno) VALUES(1,'tom',10);
2.--系统时间引发的触发器
CREATE OR REPLACE TRIGGER tri_emp
BEFORE
DELETE OR UPDATE OR INSERT
ON emp
FOR EACH ROW
DECLARE
v_dateStr VARCHAR2(20);
BEGIN
SELECT to_char(SYSDATE,'yyyy-mm-dd') INTO v_dateStr FROM dual;
IF v_dateStr = '2017-09-20' THEN
raise_application_error(-20002,'今天系统维护');
END IF;
END;
--测试是否能引发触发器
INSERT INTO emp(empno,ename,deptno) VALUES (3,'jerry',10);
六.误删除数据恢复语句
create table tableName_bak
as
select * from tableName as of TIMESTAMP to_timestamp('20081126 103435','yyyymmdd hh24miss');