Oracle数据库之第四篇

/*
授权命令 grant 权限 to 用户
授权可以授予多个权限
grant  connect,resource to baidu   
收回权限  revoke  权限 from  用户
revoke dba from baidu
创建用户 分配表空间--指定用户的默认表空间
create  table p(..) 建表存在默认表空间
--建表时候指定表空间 
create table p(...) talebspace 表空间名
*/
/*
plsql编程语言  procedure language 过程语言
是在sql语句中加入一些处理过程的语句
常见的条件表达式 if else  还有循环结构
基本结构
declare
--声明部分 理解为定义
--声明使用的变量
begin
--处理逻辑的代码块
end;
*/
--pssql简单示例
declare
v_n number := 1; --声明数值变量 赋值使用符号:=
v_s varchar2(4) :='s'; --声明字符类型变量
emp_ename emp.ename%type ;-- 引用类型变量
emp_row   emp%rowtype ;-- 记录类型变量
begin
dbms_output.put_line('v_n====='||v_n); --输出语句相当于sys out 
dbms_output.put_line('v_s====='||v_s);
select ename into emp_ename from emp where empno=7499; --使用into关键字赋值
dbms_output.put_line('emp_ename====='||emp_ename);
select  * into  emp_row    from emp where empno = 7499; --赋值记录类型变量
dbms_output.put_line('员工编号=='||emp_row.empno||'员工姓名'||emp_row.ename);
end;
/*
plsql 的条件表达式判断
if .. 处理语句 else if ..处理语句
-------------------------
if .. then  
elsif .. then  
else  
end if;   
*/
---使用条件表达式判断员工的工资 使用汉字输出
declare
emp_row   emp%rowtype ;-- 记录类型变量
begin
select  * into  emp_row    from emp where empno = 7499; --赋值记录类型变量
--使用表达式判断工资
if emp_row.sal > 3000 then
dbms_output.put_line('员工工资大于3000=='||emp_row.sal);
elsif   emp_row.sal < 1000  then
dbms_output.put_line('员工工资小于1000=='||emp_row.sal);
else
dbms_output.put_line('员工工资位于1000到3000之间=='||emp_row.sal);
end if;
end;
/*
循环结构
第一种-----
loop
exit when 条件
end loop;
第二种 ---
while 条件 loop
end loop;
第三种 ---
for 变量  in  范围 loop
end loop;
*/
-------使用循环输出数字 1-----10
/*
第一种
loop
exit when 条件
end loop;
*/
declare
v_n number :=1;
begin
loop 
--只是用来判断退出使用的,并不是相当于if()else{}
exit when v_n>10 ;   --退出条件
dbms_output.put_line(v_n);
v_n:=v_n+1;   --自增
end loop;
end;
/*
第二种
while 条件  loop
end loop;
*/
declare
v_n number :=1;
begin
while v_n<11  loop
dbms_output.put_line(v_n);
v_n:=v_n+1;   --自增
end loop;
end;
/*
第三种
for 变量 in 范围 loop  变量的声明和范围的控制是由for循环自动执行
end loop;
*/
declare
begin
for i in 1..10  loop
dbms_output.put_line(i);
end loop;
end;
/*
游标 光标  是用于接收查询的记录结果集 resultset 提示记录使用.next()
游标的使用步骤
声明游标 cursor 游标名 is select 语句 指定游标的记录结果集
打开游标  open  游标名
提取游标  fetch 游标名 into 记录类型变量 
关闭游标  close cursor
游标的两个属性  游标名%found     : 判断它有找到
游标名%notfound  : 判断它没有找到
if  emp_cursor%found then
dbms_output.put_line('found');
elsif  emp_cursor%notfound then
dbms_output.put_line('notfound');
elsif emp_cursor%notfound is null then
dbms_output.put_line('null');
end if;
*/
--使用while循环结构演示游标
declare
--声明游标
cursor emp_cursor is select * from emp;
--声明记录类型变量 用于接收游标提取的记录
emp_row  emp%rowtype; 
begin
--打开游标
open emp_cursor; 
--提取游标(判断下一个是否有值)
fetch emp_cursor into emp_row ;
--有值就执行while循环
while emp_cursor%found  loop
dbms_output.put_line(emp_row.empno||'员工姓名'||emp_row.ename);
--继续提取游标(并判断下一个是否有值)
fetch emp_cursor into emp_row ;
end loop;
close emp_cursor;
end;
/*
loop  
exit when 游标提取不到
end loop
*/
declare
--声明游标
cursor emp_cursor is select * from emp;
--声明记录类型变量 用于接收游标提取的记录
emp_row  emp%rowtype; 
begin
--打开游标
open emp_cursor; 
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line(emp_row.empno||'员工姓名'||emp_row.ename);
end loop;
close emp_cursor;
end;
--使用游标提取某个部门的员工信息
--声明带参数的游标信息
declare
--声明游标
cursor emp_cursor(dno number) is select * from emp where deptno = dno ;
--声明记录类型变量 用于接收游标提取的记录
emp_row  emp%rowtype; 
begin
--打开游标 时候传入参数
open emp_cursor(10); 
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line(emp_row.empno||'员工姓名'||emp_row.ename);
end loop;
close emp_cursor;
end;
/*
错误信息开发中的异常
数据库中叫做 例外
异常的分类 1.系统异常 系统定义好的异常
2.自定义的异常
new 自定义类继承exception 自定义传值(错误代码,提示信息)
使用场景
不满足某些特定业务场景,抛出自定义异常
异常的处理
java  try{}catche(indexoutofboundexception e){}catche(exception e){}
java  try{}catche(exception e){} catche(indexoutofboundexception e){}--报错
数据库可以捕捉处理异常
exception   关键字捕捉异常
when 异常类型 then 处理语句   判断异常类型 处理异常
*/
--异常的简单示例
/*
--除0的异常 除数为0
--赋值错误
*/
declare
v_n number :=0;
v_m number :=1;
begin
v_m:='s';  --将字符串赋值给数值变量
v_m:= v_m/v_n;
exception
when zero_divide then 
dbms_output.put_line('除数不能为0');
when value_error then
dbms_output.put_line('赋值有误');
end;
---处理太多记录数异常
declare
emp_row   emp%rowtype ;-- 记录类型变量
begin
select  * into  emp_row  from emp ; --赋值记录类型
exception
when too_many_rows then
dbms_output.put_line('太多记录数'); 
when others then    --others是最大范围的异常 相当于java 的 exception
dbms_output.put_line('其他异常');
end;
/*
需求 :使用游标查询部门下的员工信息
如果部门下没有员工 报错提示
需要自定义异常 
变量名  exception     --声明自定义异常
*/
declare
cursor emp_cursor is select * from emp where deptno= 40;  --游标结果集不存在
emp_row   emp%rowtype ;-- 记录类型变量
no_dept_emp  exception ;  --声明自定义异常
begin
open emp_cursor;  --打开游标
fetch emp_cursor into emp_row;
if emp_cursor%notfound then
--没有员工  抛出错误异常
raise no_dept_emp;
end if;
close emp_cursor;
exception
when no_dept_emp then 
dbms_output.put_line('部门下面没人,快招人吧');
end;
/*
存储过程 是一段封装好的代码块,过程是编译好放在服务器提供开发人员调用
封装的代码块意义:  提升开发效率  可以复用 谁用直接调用
提升运行效率 一调用直接运行
语法:create [or repalce]   procedure 过程名称(参数名 out|in  参数类型) 
as|is
--声明变量的部分 
begin
--处理过程语句代码块
end;
调用存储过程
在begin和end之间使用 过程名传参调用
*/
--存储过程的简单示例  使用存储过程给某个员工增加工资100
create or replace procedure add_sal(eno in number )
as
emp_sal number :=0;
begin
select sal into emp_sal from emp where empno = eno ;
dbms_output.put_line('涨工资之前是===='||emp_sal);
update emp set sal=sal+100 where empno = eno;
select sal into emp_sal from emp where empno = eno ;
dbms_output.put_line('涨工资之后是===='||emp_sal);
commit;
end;
--------调用存储过程
declare
begin
add_sal(7499);
end;
/*
使用存储过程统计某个员工的年薪,年薪需要返回输出打印
in 类型输入参数可以 省略 默认就是输入参数
*/
create or replace procedure count_sal(eno number,year_sal out number)
as
begin
select sal*12+nvl(comm,0) into year_sal  from emp where empno=eno; --使用into赋值给输出参数
end;
----调用存储过程计算年薪
declare
v_emp_sal number :=0;  
begin
count_sal(7499,v_emp_sal);
dbms_output.put_line('年薪为=='||v_emp_sal);
end;
/*
使用存储过程 查询出某个部门的员工信息
某个部门应该接受一个in类型的输入参数
查询到的部门员工多条记录返回应该使用结果集 
声明游标 cursor 游标名 is select 语句指定结果集
系统引用游标
sys_refcursor 
声明系统引用游标  变量名 sys_refcursor;  --不需要指定结果集
打开游标      open 系统引用游标 for select 语句  --使用for关键字装入数据
*/
create or replace procedure dept_emp(dno number,cusor_emp out sys_refcursor)
as
begin
--根据传进来的部门编号给游标装入结果集数据
open cusor_emp for select * from emp  where deptno = dno;   
end;
----调用存储过程查询部门下的员工
declare
cursor_emp sys_refcursor;  --声明系统引用游标传参使用
emp_row emp%rowtype ;--记录类型变量
begin
dept_emp(10,cursor_emp);
--提取游标中的数据
loop
fetch cursor_emp into emp_row;
exit when cursor_emp%notfound;
dbms_output.put_line('编号'||emp_row.empno||'姓名'||emp_row.ename);
end loop;
close cursor_emp; 
end;
/*
存储函数 是一段封装好的代码块,是编译好放在服务器提供开发人员调用
封装的代码块意义:  提升开发效率  可以复用 谁用直接调用
提升运行效率 一调用直接运行
语法:create [or repalce]   function 函数名称(参数名 out|in  参数类型) return 数据类型
in 代表传入参数,out 代表传出参数                        
as|is
--声明变量的部分 
begin
--处理过程语句代码块
--return 变量
end;
调用存储函数
在begin和end之间使用 函数名传参调用 函数必须使用变量接收 返回值
*/
--使用存储函数统计某个员工的年薪
create or replace function count_emp_sal(eno number,year_sal out number) return number
as
v_sal number :=0;
begin
select sal*12+nvl(comm,0) into year_sal  from emp where empno=eno; --使用into赋值给输出参数
return v_sal;
end;
--不带out类型输出参数统计年薪
create or replace function count_sal_noout(eno number) return number
as
v_sal number :=0;
begin
select sal*12+nvl(comm,0) into v_sal  from emp where empno=eno; --使用into赋值给输出参数
return v_sal;
end;
--调用函数统计年薪
declare
emp_sal number:=0;
total_sal number :=0;
begin
--total_sal := count_emp_sal(7499,emp_sal);
total_sal := count_sal_noout(7499);
dbms_output.put_line(emp_sal);--0
dbms_output.put_line(total_sal); --统计后年薪
end;
/*
存储函数和过程的区别
1.创建的关键字  procedure   funciton
2.创建函数 必须使用return 声明函数的返回变量数据类型
3.在函数的方法体内 必须使用return 返回一个变量
4.函数的调用 必须有变量接收返回值
5.函数可以用在select 查询语句中  select emp.*,count_sal_noout(empno) from emp;
存储函数和过程使用场景
开发规范 java代码待用过程 过程是用来处理业务逻辑代码
如果逻辑中需要用到一些功能性的封装,可以调用函数
90%情况下 函数和过程通用 过程可以调用函数,函数同样可以调用过程
*/
/*
触发器 是一个监视器,监视对表中数据的操作
如果对数据的操作满足触发器的执行条件,
触发器会自动运行
触发器语法:
create or repalce trigger 触发器名称
after|before   --触发器执行时机
insert|update|delete  --监视的动作
on 表名       --表级触发器
declare
begin          
end;
行级触发器                    insert        update        delete
:new   动作之后的记录   要插入的记录   修改后的记录     空
:old   动作之前的记录      空          原始的记录     原始的记录
*/
--创建触发器监视表,如果表中有数据插入,输出一个欢迎语句
create or replace trigger insert_trigger
after
insert
on p
declare
begin
dbms_output.put_line('欢迎加入!');
end;
----插入数据测试效果
insert into p values(1,'zs');
commit;
--插入数据不能在休息日插入数据
--休息日 周六和周日
/*
raise_application_error(v1,v2) v1错误代码  v2是提示语句
-20000 -20999 
*/
create or replace trigger insert_no_work
before
insert
on p
declare
v_day varchar2(10) ;
begin
--获取到当前星期
select to_char(sysdate,'day') into v_day from dual;
--判断星期是否在休息日
if trim(v_day)  in ('saturday','sunday') then
--如果休息 错误提示
raise_application_error(-20001,'不能休息日插入数据');
end if;
end;
----插入数据测试效果
insert into p values(1,'zs');
commit;
--使用触发器监视表中数据修改,不能做降低工资的操作
create or replace trigger can_not_low
before
update
on emp
for each row --行级触发器
declare
begin
--获取到原始记录的工资  --获取修改后的工资
if :old.sal > :new.sal then
--谈错误框提示
raise_application_error(-20002,'不能降低工资');
end if;
end;
--修改员工的工资测试触发器
update emp set sal=sal-1 where empno=7499;
/*
触发器实际应用 
使用触发器实现 插入数据的id 自增长 面试题
**/
create or replace trigger auto_increment_id
before    
insert
on test_trigger
for each row 
declare 
begin
--补全将要插入记录的id
--补全的id 是自增长的数值 如果没有提前创建序列,需要提前创建序列   --创建序列  create sequence order_sequence 
select order_sequence.nextval into :new.pid from dual;
end;
insert into test_trigger(pname,phone) values('zs','1234566');
commit;
package baidu;
import java.sql.callablestatement;
import java.sql.connection;
import java.sql.drivermanager;
import java.sql.preparedstatement;
import java.sql.resultset;
import org.junit.test;
import oracle.jdbc.oraclecallablestatement;
import oracle.jdbc.oracletypes;
public class testjdbc {
string driverclass = "oracle.jdbc.driver.oracledriver";
string url ="jdbc:oracle:thin:@192.168.17.128:1521:orcl";
string user= "baidu_03";
string password = "baidu_03";
/*
*测试jdbc连接数据库
*
* */
@test
public void queremp(){
try{
//加载驱动
class.forname(driverclass);
//获取链接
connection con = drivermanager.getconnection(url, user,password);
//获取预编译的statement
preparedstatement pst= con.preparestatement("select * from emp");
//执行查询
resultset rs =  pst.executequery();
//处理结果
while(rs.next()){
system.out.println(rs.getint(1)+"员工姓名"+rs.getstring("ename"));
}
rs.close();
con.close();
//关闭连接
}catch(exception e){
e.printstacktrace();
}
}
/*存储过程的调用
* {call <procedure-name>[(<arg1>,<arg2>, ...)]}
add_sal(eno number,addsal number)
* */
@test
public void calladdsal(){
try{
//加载驱动
class.forname(driverclass);
//获取链接
connection con = drivermanager.getconnection(url, user,password);
//获取预编译的statement
callablestatement pst= con.preparecall("{call add_sal(?,?)}");
pst.setint(1, 7499);
pst.setint(2, 1000);
//执行查询
pst.execute();
con.close();
//关闭连接
}catch(exception e){
e.printstacktrace();
}
}
/*存储过程的调用
* {call <procedure-name>[(<arg1>,<arg2>, ...)]}
count_yearsal(eno number,total_year_sal out number)
* */
@test
public void callcountsal(){
try{
//加载驱动
class.forname(driverclass);
//获取链接
connection con = drivermanager.getconnection(url, user,password);
//获取预编译的statement
callablestatement pst= con.preparecall("{call count_yearsal(?,?)}");
pst.setint(1, 7499);
//注册输出参数
pst.registeroutparameter(2, oracletypes.number);
//执行查询
pst.execute();
int total =  pst.getint(2);
system.out.println(total);
con.close();
//关闭连接
}catch(exception e){
e.printstacktrace();
}
}
/*
* pro_dept_emp(dno number,dept_emp out sys_refcursor)
* */
@test
public void callproemp(){
try{
//加载驱动
class.forname(driverclass);
//获取链接
connection con = drivermanager.getconnection(url, user,password);
//获取预编译的statement
callablestatement pst= con.preparecall("{call pro_dept_emp(?,?)}");
pst.setint(1, 10);
//注册输出参数
pst.registeroutparameter(2, oracletypes.cursor);
//执行查询
pst.execute();
oraclecallablestatement ocs = (oraclecallablestatement)pst;
resultset rs =  ocs.getcursor(2);
while(rs.next()){
system.out.println(rs.getint(1)+"员工姓名"+rs.getstring("ename"));
}
rs.close();
ocs.close();
pst.close();
con.close();
//关闭连接
}catch(exception e){
e.printstacktrace();
}
}
}
public void show4(){
try {
class.forname(driverclass);
connection con = drivermanager.getconnection(url, user,password);
callablestatement pst= con.preparecall("{?= call count_sal_noout(?)}");
//给第二个参数赋值
pst.setlong(2, 7499);
// stat2.setlong(2, empno);
//声明第一个参数的类型
pst.registeroutparameter(1, oracletypes.number);
pst.execute();
oraclecallablestatement ocs = (oraclecallablestatement)pst;
number num = ocs.getnumber(1);
system.out.println(num);
//             long i = pst.getlong(1);
//             system.out.println(i);
con.close();
} catch (exception e) {
e.printstacktrace();
}
}
/*

 

(0)
上一篇 2022年3月22日
下一篇 2022年3月22日

相关推荐