`
dingjun1
  • 浏览: 213678 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

存储过程 触发器学习

阅读更多
第一步创建一个包的声明部分:
create or replace package pac_zfda is

  -- Author  : dingjun
  -- Created : 2008-10-27 18:43:50
  -- Purpose : 做执法工作数量统计
  
  -- Public type declarations
  TYPE mycursor is REF CURSOR;--声明一个游标类型
  
  --procedure declare
  procedure p_zfda_ajtj(n_ry_bh in number,
                        c_first_time in varchar2,
                        c_last_time in varchar2,
                        c_view_name in varchar2,
                        rs out mycursor);--在这里引用了那个声明游标类型

end pac_zfda;

第二步实现包主体部分
create or replace package body pac_zfda is

       procedure p_zfda_ajtj(n_ry_bh in number,
                        c_first_time in varchar2,
                        c_last_time in varchar2,
                        c_view_name in varchar2,
                        rs out mycursor)
    is
       d_fir_day_cur_year date;--当前年份的第一天
       d_last_day_cur_year date;--当前年份的最后一天
       V_ZFDA_AJTJ varchar2(30);--视图名称
       
    begin
       d_fir_day_cur_year := to_date(c_first_time,'yyyy-mm-dd hh24:mi:ss');
       d_last_day_cur_year := to_date(c_last_time,'yyyy-mm-dd hh24:mi:ss');
       V_ZFDA_AJTJ := c_view_name;

       OPEN rs FOR select * from T_ZFDA_AJTJ_TEM;--打开刚才的游标
     
    end p_zfda_ajtj;
      

begin
  NULL;
end pac_zfda;


JAVA类调用
Connection conn = new Connection();
		CallableStatement cst = conn.prepareCall("{call pac_zfda.p_zfda_ajtj(?,?,?,?,?)}");
		cst.setLong(1, Long.parseLong("10150000000001"));
		cst.setString(2, "2008-01-01 00:00:00");
		cst.setString(3, "2008-12-31 23:59:59");
		cst.setString(4, "V_ZFDA_AJTJ");
//下面指定第三个输出参数的类型是数据集。因为java.sql.Types中没有CURSOR,所以要用oracle.jdbc.OracleTypes中的值
		cst.registerOutParameter(5, oracle.jdbc.driver.OracleTypes.CURSOR);
		cst.executeQuery();
		ResultSet rs = (ResultSet)cst.getObject(5);
		while(rs.next()){
			System.out.println(rs.getLong(1));
			System.out.println(rs.getString(2));
			System.out.println(rs.getLong(3));
			System.out.println(rs.getLong(4));
			
		}
rs.close();
cst.close();
conn.close();




以上代码中,第一步,通过TYPE建立了一个指针类型MYCURSOR。第二步,声明了:此包中有一个存储过程GET_DEC_BILL_LIST,并且,这个存储过程中有一个cur_OUT的输出变量,其类型为MYCURSOR。
CREATE OR REPLACE PACKAGE TEST.PKG_TEST IS
    TYPE MYCURSOR IS REF CURSOR;
    PROCEDURE GET_DEC_BILL_LIST(cur_OUT OUT MYCURSOR);
END;


以上代码中,实现了GET_DEC_BILL_LIST,其实质是打开了一个指针,其内容为SYS用户下的所有表的情况。这样子,数据库部分就Ready了

CREATE OR REPLACE PACKAGE BODY TEST.PKG_TEST IS
       PROCEDURE GET_DEC_BILL_LIST(cur_OUT OUT MYCURSOR) AS
       BEGIN
            OPEN cur_OUT FOR SELECT * FROM ALL_TABLES WHERE OWNER='SYS';
       END;
END;


  declare 
         cursor table_name_cur is
         SELECT t.TABLE_NAME
         FROM USER_TABLES t
         where t.table_name like 'TBL_INFOR%' and
               t.table_name not in
               (SELECT TABLE_NAME
                  FROM USER_TABLES
                 where table_name like 'TBL_INFOR%LOG');
         table_name_rec table_name_cur%Rowtype;
         old_table_name varchar2(200) ;
         new_table_name varchar2(200) ;
         row_num number;
         --sql_str varchar2(200);
 begin 
       open table_name_cur;
       loop
           fetch table_name_cur into table_name_rec;
           exit when table_name_cur%notfound;
           old_table_name := table_name_rec.table_name;
           new_table_name := CONCAT(table_name_rec.table_name,'o');
           DBMS_OUTPUT.PUT_LINE(old_table_name);
           DBMS_OUTPUT.PUT_LINE(new_table_name);
            
           DBMS_OUTPUT.PUT_LINE(row_num);
           execute immediate 'rename '|| old_table_name ||' to '||new_table_name;
       end loop;
       close table_name_cur;
 end ;




用java调用oracle存储过程总结 [转载:http://www.blogjava.net/TrampEagle/archive/2006/03/10/23605.html]
这段时间开始学习写存储过程,主要原因还是因为工作需要吧,本来以为很简单的,但几经挫折,豪气消磨殆尽,但总算搞通了,为了避免后来者少走弯路,特记述与此,同时亦对自己进行鼓励。

一:无返回值的存储过程

存储过程为:
CREATE OR REPLACE PROCEDURE TESTA(PARA1 IN VARCHAR2,PARA2 IN VARCHAR2)  AS

BEGIN 

   INSERT INTO HYQ.B_ID (I_ID,I_NAME) VALUES (PARA1, PARA2);

END TESTA;


然后呢,在java里调用时就用下面的代码:
package com.hyq.src;

 

import java.sql.*;

import java.sql.ResultSet;

 

public class TestProcedureOne {

  public TestProcedureOne() {

  }

  public static void main(String[] args ){

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

    String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521: hyq ";

    Statement stmt = null;

    ResultSet rs = null;

    Connection conn = null;

    CallableStatement cstmt = null;

 

    try {

      Class.forName(driver);

      conn =  DriverManager.getConnection(strUrl, " hyq ", " hyq ");

      CallableStatement proc = null;

      proc = conn.prepareCall("{ call HYQ.TESTA(?,?) }");

      proc.setString(1, "100");

      proc.setString(2, "TestOne");

      proc.execute();

    }

    catch (SQLException ex2) {

      ex2.printStackTrace();

    }

    catch (Exception ex2) {

      ex2.printStackTrace();

    }

    finally{

      try {

        if(rs != null){

          rs.close();

          if(stmt!=null){

            stmt.close();

          }

          if(conn!=null){

            conn.close();

          }

        }

      }

      catch (SQLException ex1) {

      }

    }

  }

}

当然了,这就先要求要建张表TESTTB,里面两个字段(I_ID,I_NAME)。

二:有返回值的存储过程(非列表)

存储过程为:
CREATE OR REPLACE PROCEDURE TESTB(PARA1 IN VARCHAR2,PARA2 OUT VARCHAR2)  AS

BEGIN 

   SELECT INTO PARA2 FROM TESTTB WHERE I_ID= PARA1; 

END TESTB;

在java里调用时就用下面的代码:
package com.hyq.src;

 

public class TestProcedureTWO {

  public TestProcedureTWO() {

  }

  public static void main(String[] args ){

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

    String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:hyq";

    Statement stmt = null;

    ResultSet rs = null;

    Connection conn = null;

    try {

      Class.forName(driver);

      conn =  DriverManager.getConnection(strUrl, " hyq ", " hyq ");

      CallableStatement proc = null;

      proc = conn.prepareCall("{ call HYQ.TESTB(?,?) }");

      proc.setString(1, "100");

      proc.registerOutParameter(2, Types.VARCHAR);

      proc.execute();

      String testPrint = proc.getString(2);

      System.out.println("=testPrint=is="+testPrint);

    }

    catch (SQLException ex2) {

      ex2.printStackTrace();

    }

    catch (Exception ex2) {

      ex2.printStackTrace();

    }

    finally{

      try {

        if(rs != null){

          rs.close();

          if(stmt!=null){

            stmt.close();

          }

          if(conn!=null){

            conn.close();

          }

        }

      }

      catch (SQLException ex1) {

      }

    }

  }

}

 

}

注意,这里的proc.getString(2)中的数值2并非任意的,而是和存储过程中的out列对应的,如果out是在第一个位置,那就是proc.getString(1),如果是第三个位置,就是proc.getString(3),当然也可以同时有多个返回值,那就是再多加几个out参数了。

三:返回列表

由于oracle存储过程没有返回值,它的所有返回值都是通过out参数来替代的,列表同样也不例外,但由于是集合,所以不能用一般的参数,必须要用pagkage了.所以要分两部分,

1,  建一个程序包。如下:
CREATE OR REPLACE PACKAGE TESTPACKAGE  AS

 TYPE Test_CURSOR IS REF CURSOR;

end TESTPACKAGE;

2,建立存储过程,存储过程为:

CREATE OR REPLACE PROCEDURE TESTC(p_CURSOR out TESTPACKAGE.Test_CURSOR) IS 

BEGIN

    OPEN p_CURSOR FOR SELECT * FROM HYQ.TESTTB;

END TESTC;

可以看到,它是把游标(可以理解为一个指针),作为一个out 参数来返回值的。

在java里调用时就用下面的代码:
package com.hyq.src;

import java.sql.*;

import java.io.OutputStream;

import java.io.Writer;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import oracle.jdbc.driver.*;

 

 

public class TestProcedureTHREE {

  public TestProcedureTHREE() {

  }

  public static void main(String[] args ){

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

    String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:hyq";

    Statement stmt = null;

    ResultSet rs = null;

    Connection conn = null;

 

    try {

      Class.forName(driver);

      conn =  DriverManager.getConnection(strUrl, "hyq", "hyq");

 

      CallableStatement proc = null;

      proc = conn.prepareCall("{ call hyq.testc(?) }");

      proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);

      proc.execute();

      rs = (ResultSet)proc.getObject(1);

 

      while(rs.next())

      {

          System.out.println("<tr><td>" + rs.getString(1) + "</td><td>"+rs.getString(2)+"</td></tr>");

      }

    }

    catch (SQLException ex2) {

      ex2.printStackTrace();

    }

    catch (Exception ex2) {

      ex2.printStackTrace();

    }

    finally{

      try {

        if(rs != null){

          rs.close();

          if(stmt!=null){

            stmt.close();

          }

          if(conn!=null){

            conn.close();

          }

        }

      }

      catch (SQLException ex1) {

      }

    }

  }

}

在这里要注意,在执行前一定要先把oracle的驱动包放到class路径里,否则会报错的。

===================================================
select   * 
  from   user_triggers 
  where   table_name=table_name
转载:http://www.souzz.net/html/database/ORACLE/20428.html
触发器 是特定事件出现的时候,自动执行的代码块。类似于存储过程,但是用户不能直接调用他们。 功能: 1、允许/限制对表的修改 2、自动生成派生列,比如自增字段 3、强制数据一致性 4、提供审计和日志记录 5、防止无效的事务处理 6、启用复杂的业务逻辑 开始 create t

触发器

是特定事件出现的时候,自动执行的代码块。类似于存储过程,但是用户不能直接调用他们。

功能:
1、 允许/限制对表的修改
2、 自动生成派生列,比如自增字段
3、 强制数据一致性
4、 提供审计和日志记录
5、 防止无效的事务处理
6、 启用复杂的业务逻辑

开始
create trigger biufer_employees_department_id
before insert or update
  of department_id
  on employees
referencing old as old_value
     new as new_value
for each row
when (new_value.department_id<>80 )
begin
:new_value.commission_pct :=0;
end;
/

触发器的组成部分:
1、 触发器名称
2、 触发语句
3、 触发器限制
4、 触发操作

1、 触发器名称
create trigger biufer_employees_department_id
命名习惯:
biufer(before insert update for each row)
employees 表名
department_id 列名

2、 触发语句
比如:
表或视图上的DML语句
DDL语句
数据库关闭或启动,startup shutdown 等等
before insert or update
  of department_id
  on employees
referencing old as old_value
     new as new_value
for each row

说明:
1、 无论是否规定了department_id ,对employees表进行insert的时候
2、 对employees表的department_id列进行update的时候

3、 触发器限制
when (new_value.department_id<>80 )

限制不是必须的。此例表示如果列department_id不等于80的时候,触发器就会执行。
其中的new_value是代表跟新之后的值。

4、 触发操作
是触发器的主体
begin
:new_value.commission_pct :=0;
end;

主体很简单,就是将更新后的commission_pct列置为0

触发:
insert into employees(employee_id,
last_name,first_name,hire_date,job_id,email,department_id,salary,commission_pct )
values( 12345,’Chen’,’Donny’, sysdate, 12, ‘donny@hotmail.com’,60,10000,.25);

select commission_pct from employees where employee_id=12345;

触发器不会通知用户,便改变了用户的输入值。


触发器类型:
1、 语句触发器
2、 行触发器
3、 INSTEAD OF 触发器
4、 系统条件触发器
5、 用户事件触发器



1、 语句触发器
是在表上或者某些情况下的视图上执行的特定语句或者语句组上的触发器。能够与INSERT、UPDATE、 DELETE或者组合上进行关联。但是无论使用什么样的组合,各个语句触发器都只会针对指定语句激活一次。比如,无论update多少行,也只会调用一次 update语句触发器。

例子:
需要对在表上进行DML操作的用户进行安全检查,看是否具有合适的特权。
Create table foo(a number);

Create trigger biud_foo
Before insert or update or delete
  On foo
Begin
If user not in (‘DONNY’) then
  Raise_application_error(-20001, ‘You don’t have access to modify this table.’);
End if;
End;
/

即使SYS,SYSTEM用户也不能修改foo表

[试验]
对修改表的时间、人物进行日志记录。

1、 建立试验表
create table employees_copy as select *from hr.employees

2、 建立日志表
create table employees_log(
  who varchar2(30),
  when date);

3、 在employees_copy表上建立语句触发器,在触发器中填充employees_log 表。
Create or replace trigger biud_employee_copy
  Before insert or update or delete
   On employees_copy
Begin
  Insert into employees_log(
   Who,when)
  Values( user, sysdate);
 
End;
/
4、 测试
update employees_copy set salary= salary*1.1;

select *from employess_log;

5、 确定是哪个语句起作用?
即是INSERT/UPDATE/DELETE中的哪一个触发了触发器?
可以在触发器中使用INSERTING / UPDATING / DELETING 条件谓词,作判断:
begin
  if inserting then
   -----
  elsif updating then
   -----
  elsif deleting then
   ------
  end if;
end;

if updating(‘COL1’) or updating(‘COL2’) then
  ------
end if;

[试验]
1、 修改日志表
alter table employees_log
  add (action varchar2(20));

2、 修改触发器,以便记录语句类型。
Create or replace trigger biud_employee_copy
  Before insert or update or delete
   On employees_copy
Declare
  L_action employees_log.action%type;
Begin
  if inserting then
   l_action:=’Insert’;
  elsif updating then
   l_action:=’Update’;
  elsif deleting then
   l_action:=’Delete’;
  else
   raise_application_error(-20001,’You should never ever get this error.’);

  Insert into employees_log(
   Who,action,when)
  Values( user, l_action,sysdate);
End;
/

3、 测试
insert into employees_copy( employee_id, last_name, email, hire_date, job_id)
values(12345,’Chen’,’Donny@hotmail’,sysdate,12);

select *from employees_log

update employees_copy set salary=50000 where employee_id = 12345;

2、 行触发器
是指为受到影响的各个行激活的触发器,定义与语句触发器类似,有以下两个例外:
1、 定义语句中包含FOR EACH ROW子句
2、 在BEFORE……FOR EACH ROW触发器中,用户可以引用受到影响的行值。
比如:

定义:
create trigger biufer_employees_department_id
before insert or update
  of department_id
  on employees_copy
referencing old as old_value
     new as new_value
for each row
when (new_value.department_id<>80 )
begin
:new_value.commission_pct :=0;
end;
/

Referencing 子句:
执行DML语句之前的值的默认名称是ld ,之后的值是 :new
insert 操作只有:new
delete 操作只有ld
update 操作两者都有

referencing子句只是将new 和old重命名为new_value和old_value,目的是避免混淆。比如操作一个名为new的表时。
作用不很大。



[试验]:为主健生成自增序列号

drop table foo;
create table foo(id number, data varchar2(20));
create sequence foo_seq;

create or replace trigger bifer_foo_id_pk
before insert on foo
for each row
begin
select foo_seq.nextval into :new.id from dual;
end;
/

insert into foo(data) values(‘donny’);
insert into foo values(5,’Chen’);
select * from foo;

3、 INSTEAD OF 触发器更新视图

Create or replace view company_phone_book as
Select first_name||’, ’||last_name name, email, phone_number,
employee_id emp_id
From hr.employees;

尝试更新email和name
update hr.company_phone_book
set name=’Chen1, Donny1’
where emp_id=100

create or replace trigger update_name_company_phone_book
INSTEAD OF
Update on hr.company_phone_book
Begin
Update hr.employees
  Set employee_id=:new.emp_id,
   First_name=substr(:new.name, instr(:new.name,’,’)+2),
   last_name= substr(:new.name,1,instr(:new.name,’,’)-1),
   phone_number=:new.phone_number,
   email=:new.email
where employee_id=:old.emp_id;
end;



4、 系统事件触发器
系统事件:数据库启动、关闭,服务器错误

create trigger ad_startup
after startup
  on database
begin
-- do some stuff
end;
/


5、 用户事件触发器
用户事件:用户登陆、注销,CREATE / ALTER / DROP / ANALYZE / AUDIT / GRANT / REVOKE / RENAME / TRUNCATE / LOGOFF

例子:记录删除对象

1. 日志表
create table droped_objects(
object_name varchar2(30),
object_type varchar2(30),
dropped_on date);

2.触发器
create or replace trigger log_drop_trigger
before drop on donny.schema
begin
insert into droped_objects values(
  ora_dict_obj_name,  -- 与触发器相关的函数
  ora_dict_obj_type,
  sysdate);
end;
/


3. 测试
create table drop_me(a number);
create view drop_me_view as select *from drop_me;
drop view drop_me_view;
drop table drop_me;

select *from droped_objects


禁用和启用触发器
alter trigger <trigger_name> disable;
alter trigger <trigger_name> enable;

事务处理:
在触发器中,不能使用commit / rollback
因为ddl语句具有隐式的commit,所以也不允许使用

视图:
dba_triggers
分享到:
评论

相关推荐

    存储过程触发器 游标

    在数据库管理中,存储过程和触发器是两个关键概念,它们极大地增强了数据库的功能性和灵活性。游标则在处理逐行数据时发挥着重要作用。本文将深入探讨存储过程、触发器和游标,以及它们在实际应用中的综合使用。 ...

    SQL Server创建存储过程、触发器、函数等(学习札记)

    SQL的存储过程、触发器等建立视图存储过程触发器函数(自定义函数)索引 视图  视图是从一个或几个基本表(或视图)导出的表。不同的是,它是一虚表,数据库中只存放视图的定义,而不存放视图对应的数据,这些数据...

    SQL Server数据库实验_存储过程与触发器设计.docx

    在实验5.1中,我们学习了如何使用`CREATE PROCEDURE`来创建存储过程,`ALTER PROCEDURE`进行修改,以及`DROP PROCEDURE`进行删除。存储过程支持不同类型的参数,包括输入参数、输出参数和返回值。例如,实验示例中...

    Oracle数据库创建存储过程和触发器

    Oracle 数据库创建存储过程和触发器 Oracle 数据库创建存储过程和触发器是高级数据库开发设计的重要组成部分。存储过程和触发器是一种...同时,我们也学习了如何创建存储过程和触发器,以及如何 troubleshoot 错误。

    存储过程和触发器的编程

    在数据库管理领域,存储过程和触发器是两个重要的概念,它们在数据操作和业务逻辑实现中扮演着不可或缺的角色。...在学习过程中,可以参考相关文档资料,如《存储过程和触发器.doc》,深入理解并熟练运用这些技术。

    实验六:创建存储过程和触发器1

    实验六的目的是深入理解并掌握SQL Server中的存储过程和触发器。存储过程是预编译的SQL语句集合,它们可以被多次调用,提高了代码的重用性和执行效率,同时降低了网络流量。以下是关于存储过程和触发器的详细解释: ...

    存储过程触发器PPT学习教案.pptx

    【存储过程】 存储过程是SQL Server 2008...通过学习存储过程的创建、调用、修改和删除,以及触发器的原理和应用,开发者和DBA能更好地维护数据库的结构和逻辑,保证数据的准确性和一致性,同时提高系统性能和安全性。

    数据库存储过程+触发器实例+权限构架

    数据库存储过程和触发器是数据库管理系统中的重要组成部分,它们在数据操作和业务逻辑控制中扮演着关键角色。权限构架则是确保系统安全性和数据完整性的重要机制。以下将详细阐述这三个核心概念及其应用。 首先,...

    Oracle连接查询子查询以及存储过程触发器讲解

    Oracle数据库是全球广泛使用的大型...通过这些PPT的学习,你将能够熟练地在Oracle数据库中进行高级查询,编写存储过程和触发器,进一步提升你的数据库管理技能。希望这些内容能帮助你在Oracle数据库的世界里游刃有余。

    存储过程和触发器语法详细讲解

    在数据库管理中,存储过程和触发器是两个重要的概念,它们在数据操作和业务逻辑实现中扮演着不可或缺的角色。本文将深入探讨这两个概念,提供详尽的语法解析,并结合实例来帮助理解它们的工作原理和应用。 一、存储...

    ORACLE PL/SQL 存储过程 触发器

    在Oracle数据库中,存储过程和触发器是两个非常重要的概念,它们在数据库管理、数据处理以及业务逻辑实现中起着关键作用。 **存储过程(Stored Procedures)** 存储过程是一组预先编译好的SQL语句和PL/SQL代码,...

    实验八数据库编程技术——游标、存储过程与触发器.pdf

    数据库编程技术——游标、存储过程与触发器 数据库编程技术是数据库管理系统中的一种重要技术,...本次实验我们学习了游标、存储过程和触发器三种数据库编程技术的应用,并通过实践了解了它们在实际应用中的重要性。

    10存储过程触发器(1)共89页.pdf.zip

    在"10存储过程触发器(1)共89页.pdf.zip"这个压缩包中,可能包含了关于如何创建、调用存储过程和触发器,以及它们在实际应用中的示例和最佳实践的详细讲解。文件列表中提到的"赚钱项目"可能指的是利用学习这些技术来...

    存储过程触发器及自定义函数PPT学习教案.pptx

    存储过程触发器及自定义函数PPT学习教案.pptx

    SQL server存储过程习题,SQL触发器习题.rar

    在SQL Server数据库管理系统中,存储过程和触发器是两种非常重要的数据库编程元素,它们对于数据库设计和数据管理...对于初学者而言,从基础语法开始,逐步深入到存储过程和触发器的学习,将对数据库管理有全面的认识。

    oralce学习笔记总结(包含存储过程触发器)

    本文件是本人学习oracle的一些总结资料,值得大家借鉴,可以互相交流

    存储过程、函数、触发器和包学习

    从概念到实例教你存储过程、函数、触发器的学习 初学者也很容易学习

    SQL_server_2008存储过程触发器

    SQL_server_2008存储过程触发器,虽然只是PPT,但是讲解的还是比较到位的,具有一定的学习价值

    存储过程触发器PPT课件.pptx

    触发器是一种特殊类型的存储过程,它会在特定的数据操作(如INSERT、UPDATE或DELETE)发生时自动执行。触发器的主要目的是强制执行复杂的业务规则和数据完整性约束,这些约束可能超出了标准的SQL约束(如主键、外键...

    存储过程触发器和函数PPT学习教案.pptx

    触发器是与特定表或视图相关联的存储过程,当对这些对象执行INSERT、UPDATE或DELETE操作时,触发器会自动执行。它们用于执行复杂的业务规则,如数据验证、审计日志记录等。 【触发器的创建和管理】 创建触发器也...

Global site tag (gtag.js) - Google Analytics