Oracle--rownum行号、rowid行地址、临时表、行转列、oracle的分页、视图、序列、索引、同义词、循环、光标、存储过程,函数、触发器

本文深入探讨Oracle数据库技术,包括rownum行号的使用,rowid行地址的理解,临时表的创建及其特性,行转列的wm_concat函数,以及分页查询。此外,还详细讲解了视图的概念和优点,序列的创建与应用,索引的创建、使用场景及优缺点,同义词的作用和创建,以及PL/SQL中的流程控制、光标、异常处理、存储过程和函数等核心概念。

3.1 rownum行号

SQL> select rownum,e.* from emp e;

  1. rownum永远按照默认的顺序生成

SQL> select rownum,e.ename,e.sal from emp e order by sal desc;

  1. rownum只能使用 < <=; 不能使用> >=

 

3.2 rowid行地址

SQL> select rowid,empno,ename,sal from emp;

SQL> select * from emp where rowid='AAAMfPAAEAAAAAgAAA';

 

3.3 临时表

1. create global temporary table *****

2. 自动创建: order by

特点:当事务或者会话结束的时候,表中的数据自动删除

SQL> create global temporary table tmp_table1 (tid number,tname varchar2(20)) on commit delete rows;

SQL> insert into tmp_table1 values (1,'Tom');

SQL> select * from tmp_table1;

SQL> commit;【commit后,数据会消失】

SQL> desc tmp_table1;

 

3.4行转列

  1. wm_concat(varchar2) 组函数

 

SQL> select deptno,wm_concat(ename) namelist from emp group by deptno;

 

 

第一题:【oracle的分页】

  1. 找到员工表中工资最高的前三名

select e.ename,e.sal

from (select * from emp order by sal desc) e

where rownum <=3

  1. 分页这样写是不对的】,rownum不能使用> >=

select e.ename,e.sal

from (select * from emp order by sal desc) e

where rownum >=3 and rownum <=6

  1. 分页的一种正确写法

select * from

(select rownum r,e.*

from (select * from emp order by sal) e

where rownum <=6)

where r>3

 

 

第二题:

  1. 找到员工表中薪水大于本部门平均薪水的员工
  1. 求出部门的平均工资
  2. 判断员工是否工资大于本部门的平均工资

第一种写法

select e.empno,e.ename,e.sal,d.avgsal

from

emp e, (select deptno,avg(sal) avgsal from emp group by deptno) d

where e.deptno=d.deptno and e.sal > d.avgsal

第二种写法:【相关子查询:将主查询中的值 作为参数传递给子查询】

select e.empno,e.ename,e.sal,(select avg(sal) from emp where deptno = e.deptno) avgsal

from emp e

where e.sal > (select avg(sal) from emp where deptno = e.deptno)

第三种写法:

select * from emp e1 where sal > (select avg(sal) from emp e2 where e2.deptno=e1.deptno group by deptno);

 

 

第三题:

  1. 计算每年入职的员工数

 

select count(*) Total,

sum(decode(to_char(hiredate,'yyyy'),'1980',1,0)) "1980",

sum(decode(to_char(hiredate,'yyyy'),'1981',1,0)) "1981",

sum(decode(to_char(hiredate,'yyyy'),'1982',1,0)) "1982",

sum(decode(to_char(hiredate,'yyyy'),'1987',1,0)) "1987"

from emp

 

4数据处理

4.1SQL 的类型

  1. 1. DML(data manipulation Language 数据操作语言): insert  update delete select
  2. 2. DDL(Data Definition Language 数据定义语言):

create table,alter table,drop table,truncate table

create/drop view,sequence(序列),index,synonym(同义词)

  1. 3. DCL(Data Control Language 数据控制语言): grant(授权) revoke(撤销权限)

4.2 例子

 

PreparedStatement

预处理

insert into emp (empno,ename,sal,deptno) values (?,?,?,?);

地址符 &

SQL>insert into emp (empno,ename,sal,deptno) values (&empno,&ename,&sal,&deptno)

SQL> select empno,ename,sal,&t from emp;

SQL> select * from &t;

批处理

复制表结构

SQL> create table emp10 as select * from emp where 1=2;

一次性将emp中,所有10号部门的员工插入到emp10中

SQL> insert into emp10 select * from emp where deptno=10;

delete和truncate的区别:

1. delete逐条删除;truncate先摧毁表,再重建

2.(根本)delete是DML(可以回滚),truncate是DDL(不可以回滚)

3. delete不会释放空间 truncate会

4. delete可以闪回 (flashback),  truncate不可以

5. delete会产生碎片;truncate不会

SQL> set feedback off

SQL> @C:\课程\JavaEE\oracle【3天】\资料\testdelete.sql

SQL> select count(*) from testdelete;

SQL> set timing on

SQL> delete from testdelete;

SQL> drop table testdelete purge;

SQL> @C:\课程\JavaEE\oracle【3天】\资料\testdelete.sql

SQL> truncate table testdelete;

SQL> set feedback on

SQL> set timing off

 

事务的标致

 1. 起始标志:事务中第一条DML语句

 2. 结束标志:提交: 显式 commit

                     隐式 正常退出(exit),DDL,DCL

              回滚:   显式 rollback

                     隐式 非正常退出,掉电,宕机

保存点

SQL> create table testsavepoint (tid number, tname varchar2(20));

SQL> insert into testsavepoint values(1,'Tom');

SQL> insert into testsavepoint values(2,'Mary');

SQL> savepoint a;

SQL> insert into testsavepoint values(3,'Maake');

SQL> select * from testsavepoint;

SQL> rollback to savepoint a;

SQL> select * from testsavepoint;

SQL> commit;

SQL> set transaction read only;

SQL> select * from testsavepoint;

SQL>insert into testsavepoint values(3,'Maake');【不能在 READ ONLY 事务处理中执行插入/删除/更新操作

SQL> rollback;

 

 

5创建和管理表

表创建

SQL> create table test3(tid number,tname varchar2(20),hiredate date default sysdate);

SQL> insert into test3(tid,tname) values(1,'Tom');

SQL> select * from test3;

 

创建表,保存20号部门的员工

SQL> create table emp20 as select * from emp where deptno=20;

 

创建表,员工号 姓名  月薪 年薪 部门名称

SQL> create table empinfo

as

select e.empno,e.ename,e.sal,e.sal*12 annsal,d.dname

from emp e,dept d

where e.deptno=d.deptno

 

添加表字段

SQL> alter table test3 add photo blob;

修改表字段

SQL> alter table test3 modify tname varchar2(40);

删除表字段

SQL> alter table test3 drop column photo;

重命名表字段

SQL> alter table test3 rename column tname to username;

改表名

SQL> rename test3 to test5;

删除表

SQL> drop table test5

显示回收站

SQL> show recyclebin

清空回收站

SQL> purge recyclebin;

删除的表,可以从回收站查询

SQL> drop table TESTSAVEPOINT;

SQL> select * from "BIN$ULtYrrqvTlqfr+qeSXIHNA==$0";

闪回删除

SQL> flashback table TESTSAVEPOINT to before drop;

注意:管理员没有回收站sys

 

创建约束表字段

SQL>create table test5

(tid number,

tname varchar2(20),

gender varchar2(2) check (gender in ('','')),

sal number check(sal > 0)

)

SQL> insert into test5 values(1,'Jone','男',1000);

SQL> insert into test5 values(1,'Jone','A',1000);【违反检查约束条件 (SCOTT.SYS_C005420)

SQL> insert into test5 values(1,'Jone','',-10);

 

外键关联

SQL>create table student

(sid number constraint student_pk primary key,

sname varchar2(20) not null,

deptno number constraint student_fk references dept(deptno))

SQL> insert into student values (1,'Jone',10);

 

 

6视图

6.1常见的数据库对象

对象

描述

基本的数据存储集合,由行和列组成

视图

从表中抽出的逻辑上的相关的数据集合

序列

提供有规律的数值

索引

提搞查询的效率

同义词

给对象起别名

 

 

6.2视图

  1. 视图是一张虚表
  2. 视图建立在已有表的基础,视图赖以建立的这些表称为基表
  3. 向视图提供数据的内容的语句为select语句,可以将视图理解为存储起来的select语句
  4. 视图是向用户提供基表数据的另一种形式

 

6.3视图的优点

  1. 限制数据访问
  2. 简化复杂查询
  3. 提供数据的相互独立
  4. 同样的数据可以有不同的显示方式
  5. 但视图不能提高性能

 

ora-01034 oracle not acailable

 

 

添加权限

虚拟机里以管理员登录,并授权scott的视图权限

SQL> sqlplus sys/manager as sysdba

SQL> grant create view to scott

创建视图

SQL>create view empinfoview

as

select e.empno,e.ename,e.sal,e.sal*12 annsal,d.dname

from emp e,dept d

where e.deptno=d.deptno

查看视图结构

SQL> desc empinfoview;

查询视图

SQL> select * from empinfoview;

只读视图

SQL>create or replace view empinfoview

as

select e.empno,e.ename,e.sal,e.sal*12 annsal,d.dname

from emp e,dept d

where e.deptno=d.deptno

with read only

 

 

 

 

7 序列

7.1 序列

  1. 可供多个用户用来产生唯一数值的数据库对象
  2. 自动提供惟一的数值
  3. 共享对象
  4. 主要用于提供主键
  5. 将序列值装入内存可以提高访问效率

 

7.2创建序列

 

SQL> create sequence myseq;

 

SQL> create table testseq(tid number,tname varchar2(20));

 

SQL> select myseq.nextval from dual;

 

SQL> select myseq.currval from dual;

 

SQL> insert into testseq values(myseq.nextval,'aa');

SQL> insert into testseq values(myseq.nextval,'aa');

SQL> insert into testseq values(myseq.nextval,'aa');

SQL> slect * from testseq;

SQL> commit;

SQL> insert into testseq values(myseq.nextval,'aa');

SQL>rollback

 

8 索引

8.1 索引

  1. 一种独立于表的模式对象,可以存储在与表不同的磁盘或者表空间
  2. 索引被删除或者损坏,不会对表产生影响,其影响只是查表的速度
  3. 索引一旦被建立,oracle管理系统会对其进行自动维护,而且由oracle管理系统决定何时使用索引,用户不用在查询查询语句中指定使用哪个索引
  4. 在删除一个表时,所有基于该表的索引会自动被删除
  5. 通过指针加速oracle服务器的查询速度
  6. 通过快速定位的方法,减少磁盘的I/O

 

索引可以提高查询速度,我们只需要创建索引,至于怎么使用索引,是oracle系统内部的事情

 

 

8.2 什么情况下创建索引

  1. 列中数据值分布很广
  2. 列经常在where语句或连接条件中出现
  3. 表经常被访问,而且量很大,访问的数据大概占总量的2%~4%

 

8.3 什么情况下不要创建索引

  1. 表很小
  2. 经常更新
  3. 列不经常在where语句或连接条件中出现

 

8.4 创建索引

 

SQL> create index myindex on emp();

 

 

9 同义词

9.1 同义词 取别名

  1. 使用同义词访问其它对象
  2. 方便访问其它用户的对象
  3. 缩短对象名字的长度
  4. 创建同义词需要授权grant create synonym to scott

 

9.2 使用

 

SQL> create synonym myemp for emp;

SQL> select * from myemp;

 

SQL> create synonym hremp for hr.employees;

SQL> grant select on hr.employees to scott【需要授权才能访问其它用户的表】

SQL> select count(*) from hr.employees;

SQL> select count(*) from hremp;

 

 

使用oracle的图形化工具

 

1 PL/SQL

1.1什么是PL/SQL?

  1. PL:Process Language
  2. PL/SQL是oracle对sql语言的过程化扩展
  3. 在SQL语言中添加了过程处理语句(如分支,循环),使SQL语言具有过程处理能力

 

1.2 PL/SQL程序结构

Declare

  说明部分 (变量、光标、例外声明)

Begin

  语句序列(DML)...

Exception

  例外处理语句

End;

 

1.3变量声明

  1. 可以声明的变量类型 char,varchar2,boolean,date,number,long

--查找7839的员工信息

--打开输出

set serveroutput on

declare

  pename emp.ename%type;--名字变量

  psal emp.sal%type;--薪水变量

begin

  select ename,sal into pename,psal from emp where empno=7839;

  --输出

  DBMS_OUTPUT.PUT_LINE(pename||'的薪水是'||psal);

end;

1.4 if语句

--判断用户从键盘输入的数字

--打开输出

set serveroutput on

--num是地址值,用来保存输入的值

accept num prompt '请输入一个数字'

declare

  pnum number :=&num;

begin

  if pnum = 0 then dbms_output.put_line('你输入的是0');

  elsif pnum = 1 then dbms_output.put_line('你输入的是1');

  elsif pnum = 2 then dbms_output.put_line('你输入的是2');

  else dbms_output.put_line('其它数字');

  end if;

end;

 

 

 

1.5循环

--打开输出

set serveroutput on

declare

  pnum number :=1;

begin

  loop

  exit when pnum > 10;

  dbms_output.put_line(pnum);

  pnum :=pnum + 1;

  end loop;

end;

 

1.6光标

  1. 光标(cursor)也被称为游标。Oracle 使用两种光标:显示光标和隐式光标。
  2. 不管语句返回多少条纪录, PL/SQL 为使用的每一条 UPDATE 、 DELETE 和 INSERT 等 SQL 命令隐式的声明一个光标。

 

  1. 光标的作用
  2. 当 PL/SQL 光标查询返回多行数据时,这些记录组被称为活动集。 Oracle 将这种活动集存储在您创建的显示定义的已命名的光标中。Oracle 光标是一种用于轻松的处理多行数据的机制,没有光标, Oracle 开发人员必须单独地、显示地取回并管理光标查询选择的每一条记录。
  3. 光标的另一项功能事,它包含一个跟踪当前访问的记录的指针,这使您的程序能够一次处理多条记录。

 

  1. 练习

遍历员工薪水

set serveroutput on

 

declare

  cursor cemp is select ename,sal from emp;

  pename emp.ename%type;

  psal emp.sal%type;

begin

  --打开光标

  open cemp;

  loop

    fetch cemp into pename,psal;

    exit when cemp%notfound;

    dbms_output.put_line(pename||'的薪水是'||psal);

  end loop;

  --关闭光标

  close cemp;

end; 

涨工资,总裁1000 经理800 其他400

set serveroutput on

 

declare

  --jobplsql中是一个关键字,重命名一下

  --alter table "SCOTT"."EMP" rename column "JOB" to empjob

  cursor cemp is select empno,empjob from emp;

  pempno emp.empno%type;

  pjob emp.empjob%type;

begin

  --rollback;

  --打开光标

  open cemp;

  loop

    fetch cemp into pempno,pjob;

    exit when cemp%notfound;

      if pjob='PRESIDENT' then update emp set sal = sal + 1000 where empno=pempno;

      elsif pjob='MANAGER' then update emp set sal = sal + 800 where empno=pempno;

      else  update emp set sal = sal + 400 where empno=pempno;

      end if;

  end loop;

  --关闭光标

  close cemp;

  --需要提交

  commit;

end; 

带参数的光标

set serveroutput on

 

declare

  cursor cemp(dNo number) is select ename,sal from emp where deptno = dNo;

  pename emp.ename%type;

  psal emp.sal%type;

begin

  --打开光标

  open cemp(20);

  loop

    fetch cemp into pename,psal;

    exit when cemp%notfound;

    dbms_output.put_line(pename||'的薪水是'||psal);

  end loop;

  --关闭光标

  close cemp;

end; 

 

 

  1. 默认,一个会话中只能打开300个光标

SQL> show parameter cursor【只能系统管理员可查看】

SQL>alter system set open_cursors=400; 【修改】

 

1.7例外(异常)

  1. 例外是程序设计语言提供的一种功能,用来增强程序的键壮性和容错性
  2. oracle的异常处理
  3. 系统定义的例外【异常】
    1. No_data_found【没有找到数据】
    2. Too_many_row【select ...into语句匹配多个行】
    3. Zero_Divide【被零除】
    4. Value_error 【算术或转换错误】
    5. Timeout_on_resource【在等待资源时发生超时】

 

系统异常

set serveroutput on

 

declare

  pnum number;

begin

  pnum:=1/0;

  --pnum:='b';

exception

  when zero_divide then DBMS_OUTPUT.PUT_LINE('0不能做分母');

                        DBMS_OUTPUT.PUT_LINE('0不能做分母');--可写多行

  when value_error then  DBMS_OUTPUT.PUT_LINE('算术转换异常');

  when others then  DBMS_OUTPUT.PUT_LINE('其它导常');

end; 

 

自定义异常

--查询50号部门的员工姓名

set serveroutput on

 

declare

  cursor cemp is select ename from emp where deptno=50;

  pename emp.ename%type;

 

  --自定义异常

  no_emp_found exception;

begin

  open cemp;

 

  --取第一条记录

  fetch cemp into pename;

 

  if cemp%notfound then

    --抛出异常

    raise no_emp_found;

  end if;

 

  close cemp;

 

exception

  when no_emp_found then dbms_output.put_line('没有找到员工');

  when others then dbms_output.put_line('其他例外');

end;

 

1.8案例

  1. 统计每年入职的员工数

set serveroutput on

declare

  cursor cemp is select to_char(hiredate,'yyyy') from emp;

  phiredate varchar2(4);

  --声明变量

  count80 number :=0;

  count81 number :=0;

  count82 number :=0;

  count87 number :=0;

begin

  open cemp;

  loop

    fetch cemp into phiredate;

    exit when cemp%notfound;

   

    if phiredate = '1980' then count80:=count80+1;

    elsif phiredate = '1981' then count81:=count81+1;

    elsif phiredate = '1982' then count82:=count82+1;

    else count87:=count87+1;

    end if;

  end loop;

  close cemp;

 

  DBMS_OUTPUT.PUT_LINE('Total'||(count80 + count81 + count82 + count87));

  DBMS_OUTPUT.PUT_LINE('1980'||count80);

  DBMS_OUTPUT.PUT_LINE('1981'||count81);

  DBMS_OUTPUT.PUT_LINE('1982'||count82);

  DBMS_OUTPUT.PUT_LINE('1987'||count87);

end;

  1.  

1.9案例

  1. 为员工涨工资。从最低工资起,每人涨10%,但总额不能超过5W,请计算涨工资的人数和长工资后的工资总额

 

/**

1.为员工涨工资。从最低工资起,每人涨10%

2.但总额不能超过5W,请计算涨工资的人数和长工资后的工资总额

 

1.声明变量

涨工资的人数 countEmp number:0;

涨工资的总额 salTotal number;

[select sum(sal) into salTotal from emp];

2.得到初始的工资总和

3.光标遍历

4.如果总额大于5000就不加工资

*/

 

set serveroutput on

declare

  cursor cemp is select empno,sal from emp order by sal;

  pempno emp.empno%type;

  psal emp.sal%type;

 

  countEmp number:=0;--涨工资的人数

  salTotal number;--工资的总额

begin

  --获取当前总工资

  select sum(sal) into salTotal from emp;

  open cemp;

  loop

    --大于5W不在加工资

    exit when salTotal > 50000;

    fetch cemp into pempno,psal;

    --没有光标,无下条记录

    exit when cemp%notfound;

    --涨工资

    update emp set sal = sal*1.1 where empno=pempno;

   

    --涨工资人数

    countEmp :=countEmp+1;

    --涨后金额

    salTotal :=salTotal + psal*0.1;

  end loop;

  close cemp;

  commit;--提交事务

  DBMS_OUTPUT.PUT_LINE('涨工资人数'||countEmp);

  DBMS_OUTPUT.PUT_LINE('涨后工资总额'||salTotal);

end;

 

2.0案例

  1. 实现按部门分段(6000以上),(6000,3000),3000元以下统计各工资段的职工人数,以及各部门的工资总和

 

/*

1.部门 遍历打印部门编号

2.部门员工遍历,薪水

3.声明三个区间的变量

4.声明部门总工资变量

*/

 

set serveroutput on

declare

  --部门光标

  cursor cdept is select deptno from dept;

  --部门ID变量

  pdeptno dept.deptno%type;

 

  --员工光标

  cursor cemp(dNo number) is select sal from emp where deptno=dNo;

  psal emp.sal%type;

 

  --每个区间的员工个数

  count1 number;-->6000

  count2 number;--<3000

  count3 number;--3000~600

 

  totalSal number;--部门上总工资

begin

  --打开光标

  open cdept;

  --1.遍历部门

  loop

    count1:=0;count2:=0;count3:=0;

   

    fetch cdept into pdeptno;

    exit when cdept%notfound;

   

    select sum(sal) into totalSal from emp where deptno = pdeptno;

    --打印部门编号

    DBMS_OUTPUT.PUT_LINE ('部门编号'||pdeptno ||'总工资'||nvl(totalSal,0));

   

    --2.根据部门编号遍历员工

    open cemp(pdeptno);

    loop

      fetch cemp into psal;

      exit when cemp%notfound;

      --打印工资

      --DBMS_OUTPUT.PUT_LINE ('--'||psal);

      --3.遍历员工工资区间

      if psal>6000 then count1 :=count1+1;

      elsif psal<3000 then count2 :=count2+1;

      else count3 :=count3+1;

      end if;

    end loop;

    close cemp;

  

    --打印工资区间人数

    DBMS_OUTPUT.PUT_LINE ('工资>6000:'||count1||' 工资<3000:'||count2||' 工资3000~6000:'||count3);

    DBMS_OUTPUT.PUT_LINE ('=========================================');

  --结束循环 

  end loop;

  --关闭光标

  close cdept;

end;

 

2 存储过程,函数

2.1存储过程和存储函数

  1. 指存储在数据库中供所有用户程序调用的子程序叫存储过程和存储函数

2.2创建存储过程语法

Create [or replace] procedure 过程名(参数)

as

    PLSQL子程序

 

  1. 无参数的存储过程

--创建一个存储过程

create or replace procedure sayHelloWord

as

  --说明部份

begin

  DBMS_OUTPUT.PUT_LINE('Hello Word');

end;

 

 

--调用存储过程 第一方式

EXECUTE sayHelloWord();

 

--调用存储过程 第二方式

begin

  sayHelloWord();

  sayHelloWord();

end;

  1. 带参数的存储过程

--给指定的员工涨工资100,并且涨前涨后的薪水

create or replace procedure raisesalary(eno in number)

as

  psal emp.sal%type;

begin

  --得到当前薪水

  select sal into psal from emp where empno = eno;

 

  --涨100

  update emp set sal=sal+100 where empno=eno;

  --打印

  DBMS_OUTPUT.put_line('涨前:'||psal||' 涨后:'||(psal + 100));

 

end;

 

--调用存储过程

set serveroutput on

begin

 raisesalary(7369);

 raisesalary(7369);

 --需要在这里提交事务,不要在内部提交

 commit;

end;

 

 

2.3存储过程的调试

  1. 如图,存储过程可调试,但在调试前需要给于权限
  2. 然后加断点调试,先选择调用,用法跟java的调试差不多

授权

 

 

2.4存储函数

  1. 函数(Function)为一命名的存储函数,可以带参数,并返回一计算值。函数和过程的结构相似,但必需要有一个return语句,用于返回函数值。函数说明要指定函数名、结果值的类型,以及参数类型。

 

2.5创建存储函数语法

Create [or replace] function 函数名(参数)return 返回值类型

as

    PLSQL子程序

 

函数声明 【计算年薪】

create or replace function queryincome(eno in number) return number

as

  psal emp.sal%type;--月薪

  pcomm emp.comm%type;--奖金

begin

  --得到当前月薪和奖金

  select sal,comm into psal,pcomm from emp where empno = eno;

 

  --返回年收入

  return psal*12 + nvl(pcomm,0);

 

end;

函数调用

set serveroutput on

--函数的调用

declare

  y_sal number;

begin

  y_sal:=queryincome(7369);

  DBMS_OUTPUT.put_line('年薪:'||y_sal);

end;

 

2.6 什么时候用存储函数和存储过程

  1. 如果有一个返回值就用存储函数,否则就用存储过程

 

 

3 java中调用存储过程和函数

创建一个存储过程【根据员工编号返回员工名字和工资】

create or replace procedure queryempinfo(eno in number,empname out varchar,empsal out number)

as

  psal emp.sal%type;

begin

  select ename,sal into empname,empsal from emp where empno = eno;

end;

创建一个java项目,导入ojdbc和junit

写一个JDBC工具包

package demo;

 

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Statement;

 

public class JDBCUtils {

 

         private static String driver = "oracle.jdbc.OracleDriver";

         private static String url = "jdbc:oracle:thin:@192.168.56.102:1521:orcl";

         private static String user = "scott";

         private static String password = "scott";

        

         static{

                  try {

                          Class.forName(driver);

                  } catch (ClassNotFoundException e) {

                          // TODO: handle exception

                          e.printStackTrace();

                  }

         }

        

         /**

          * 返回一个数据连接

          * */

         public static Connection getConnection(){

                  try {

                          return DriverManager.getConnection(url, user, password);

                  } catch (SQLException e) {

                          // TODO Auto-generated catch block

                          e.printStackTrace();

                  }

                 

                  return null;

         }

        

         public static void rlease(Connection conn,Statement st,ResultSet rs){

                 

                  if(rs!=null){

                          try {

                                   rs.close();

                          } catch (SQLException e) {

                                   // TODO Auto-generated catch block

                                   e.printStackTrace();

                          }finally{

                                   rs = null;//释放

                          }

                  }

                 

                  if(st != null){

                          try {

                                   st.close();

                          } catch (SQLException e) {

                                   // TODO Auto-generated catch block

                                   e.printStackTrace();

                          }finally{

                                   st = null;//释放

                          }

                  }

                 

                  if(conn != null){

                          try {

                                   conn.close();

                          } catch (SQLException e) {

                                   // TODO Auto-generated catch block

                                   e.printStackTrace();

                          }finally{

                                   conn = null;//释放

                          }

                  }

         }

}

 

存储过程的调用

@Test

    public void testProcedure(){

       //存储过程的java写法{call <procedure-name>[(<arg1>,<arg2>, ...)]}

       String p = "{call queryempinfo(?,?,?)}";

      

       Connection con =null;

       CallableStatement call = null;

      

       try {

           con = JDBCUtils.getConnection();

           call = con.prepareCall(p);

           //对于in参数,赋值

           call.setInt(1, 7369);

          

           //设置out参数类型

           call.registerOutParameter(2, OracleTypes.VARCHAR);

           call.registerOutParameter(3, OracleTypes.NUMBER);

          

           //执行

           call.execute();

           //取结果

           String ename = call.getString(2);

           double sal = call.getDouble(3);

           System.out.println(ename);

           System.out.println(sal);

          

       } catch (SQLException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }finally {

          JDBCUtils.rlease(con, call, null);

      }

    }

存储函数的调用{?=call <funtion-name>[(<arg1>,<arg2>, ...)]}

@Test

    public void testFunction(){

       //存储方法的java写法{?=call <funtion-name>[(<arg1>,<arg2>, ...)]}

       String p = "{?=call queryincome(?)}";

      

       Connection con =null;

       CallableStatement call = null;

      

       try {

           con = JDBCUtils.getConnection();

           call = con.prepareCall(p);

           //对于in参数,赋值

           call.setInt(2, 7369);

          

           //设置out参数类型

           call.registerOutParameter(1, OracleTypes.NUMBER);

          

           //执行

           call.execute();

           //取结果

           double y_sal = call.getDouble(1);

           System.out.println(y_sal);

          

       } catch (SQLException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }finally {

           JDBCUtils.rlease(con, call, null);

       }

    }

 

4 触发器

4.1触发器定义

  1. 数据库触发器是一个与表相关联、存储的PL/SQL程序。每当一个特定的数据操作语句(Insert,Update,delete)在指定的表上发出时,Oracle自动地执行触发器中定义的语句序列。
  2. 触发器的类型
    1. 语句级触发器
      1. 在指定的操作语句操作之前或之后执行一次,不管这条语句影响了多少行。
  1. 行级触发器(FOR EACH ROW)
    1. 触发语句作用的每一条记录都被触发。在行级触发器使用:old和:new 伪记录变量,识别值的状态

 

4.2触发器语法格式

CREATE [or REPLACE] TRIGGER 触发器名

{BEFORE | ALTER}

{DELETE | INSERT | UPDATE [OF 列名]}

ON 表名

[FOR EACH ROW [WHEN(条件)]]

PLSQL

 

 

4.3案例

  1. 第一个触发器,插入员工后打印一句输出

create trigger abcd after insert on emp

declare

 

begin

  DBMS_OUTPUT.PUT_LINE('成功插入新员工');

end;

 

set serveroutput on

insert into emp (empno,ename,sal,deptno) values(1122,'zhangsan',1920,10);

2.实施复杂的安全性检查 禁止在非工作时间插入新员工

create trigger securityemp before insert on emp

begin

  if to_char(sysdate,'day') in ('星期六','星期日') or

  to_number(to_char(sysdate,'hh24')) not between 9 and 17

  then RAISE_APPLICATION_ERROR(-20001, '禁止非工作时间插入新员工');

  end if;

end;

 

set serveroutput on

insert into emp (empno,ename,sal,deptno) values(1432,'zhangsan3',1920,10);

commit;

3涨后的工资不能少于涨前的工资

create or replace trigger checksalary

before update

on emp

for each row

begin

  if :new.sal < :old.sal  then

  raise_application_error(-20002,'涨后的工资不能少于涨前的工资new:'||:new.sal||' old:'||:old.sal);

  end if;

end;

 

set serveroutput on;

update emp set sal = sal -10 where empno=1122;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值