/* 授权命令 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(); } } /*