精华内容
下载资源
问答
  • 在BORROW表上建立一个触发器,完成如下功能:如果读者借阅的书名是"数据库技术及应用",就将该读者的借阅记录保存在BORROW_SAVE表中(注ORROW_SAVE表结构同BORROW表)在网上能搜到这题的答案,但是就是不理解,放在...

    在BORROW表上建立一个触发器,完成如下功能:如果读者借阅的书名是"数据库技术及应用",就将该读者的借阅记录保存在BORROW_SAVE表中(注ORROW_SAVE表结构同BORROW表)

    在网上能搜到这题的答案,但是就是不理解,放在自己的MySQL上运行不起来,所以我就自己写了一个经过测试能在MySQL上运行的程序

    delimiter $

    create trigger mybr after insert on borrow for each row

    begin

    insert into borrow_save select * from borrow

    where bno=(select bno from books where bname='数据库技术及应用')

    and cno=new.cno and bno=new.bno;

    end $

    delimiter

    上面是直接插入borrow_save表中,如果没有borrow_save表可以创建表,可以这样写

    delimiter $

    create trigger mybr after insert on borrow for each row

    begin

    create table  borrow_save (select * from borrow

    where bno=(select bno from books where bname='数据库技术及应用')

    and cno=new.cno and bno=new.bno);

    end $

    delimiter

    展开全文
  • 声明此触发器:CREATE TRIGGER my_triggerBEFORE UPDATEON my_tableFOR EACH ROWCALL "com.example.MyTrigger"使用Java / JDBC实现触发器:public class MyTrigger implements Trigger {@Overridepublic void init...

    声明此触发器:

    CREATE TRIGGER my_trigger

    BEFORE UPDATE

    ON my_table

    FOR EACH ROW

    CALL "com.example.MyTrigger"

    使用Java / JDBC实现触发器:

    public class MyTrigger implements Trigger {

    @Override

    public void init(Connection conn, String schemaName,

    String triggerName, String tableName, boolean before, int type)

    throws SQLException {}

    @Override

    public void fire(Connection conn, Object[] oldRow, Object[] newRow)

    throws SQLException {

    try (PreparedStatement stmt = conn.prepareStatement(

    "INSERT INTO log (field1, field2, ...) " +

    "VALUES (?, ?, ...)")

    ) {

    stmt.setObject(1, newRow[0]);

    stmt.setObject(2, newRow[1]);

    ...

    stmt.executeUpdate();

    }

    }

    @Override

    public void close() throws SQLException {}

    @Override

    public void remove() throws SQLException {}

    }

    使用jOOQ实现触发器:

    由于您在问题中添加了jOOQ标记,我怀疑这种替代方案也可能是相关的.你当然可以在H2触发器中使用jOOQ:

    @Override

    public void fire(Connection conn, Object[] oldRow, Object[] newRow)

    throws SQLException {

    DSL.using(conn)

    .insertInto(LOG, LOG.FIELD1, LOG.FIELD2, ...)

    .values(LOG.FIELD1.getDataType().convert(newRow[0]),

    LOG.FIELD2.getDataType().convert(newRow[1]), ...)

    .execute();

    }

    展开全文
  • 触发器的组成部分:触发器的声明,指定触发器定时,事件,表名以类型触发器的执行,PL/SQL块或对过程的调用触发器的限制条件,通过where子句实现类型:应用程序触发器,前台开发工具提供的;数据库触发器,定义在...

    a901c1a3aebafc8e85930fcde98d8cf1.png

    DML触发器有三类:

    1, insert触发器;

    2, update触发器;

    3, delete触发器;

    触发器的组成部分:

    触发器的声明,指定触发器定时,事件,表名以类型

    触发器的执行,PL/SQL块或对过程的调用

    触发器的限制条件,通过where子句实现

    类型:

    应用程序触发器,前台开发工具提供的;

    数据库触发器,定义在数据库内部由某种条件引发;分为:

    DML触发器;

    数据库级触发器;

    替代触发器;

    DML触发器组件:

    1,触发器定时

    2,触发器事件

    3,表名

    4, 触发器类型

    5, When子句

    6, 触发器主体

    可创建触发器的对象:数据库表,数据库视图,用户模式,数据库实例

    创建DML触发器:

    Create [or replace] trigger [模式.]触发器名

    Before| after   insert|delete|(update of 列名)

    On 表名

    [for each row]

    When 条件

    PL/SQL块

    For each row的意义是:在一次操作表的语句中,每操作成功一行就会触发一次;不写的话,表示是表级触发器,则无论操作多少行,都只触发一次;

    When条件的出现说明了,在DML操作的时候也许一定会触发触发器,但是触发器不一定会做实际的工作,比如when 后的条件不为真的时候,触发器只是简单地跳过了PL/SQL块;

    Insert触发器的创建:

    create or replace trigger tg_insert

    before insert on student

    begin

    dbms_output.put_line('insert trigger is chufa le .....');

    end;

    /

    执行的效果:

    SQL> insert into student

    2 values(202,'dongqian','f');

    insert trigger is chufa le .....

    update表级触发器的例子:

    create or replace trigger tg_updatestudent

    after update on student

    begin

    dbms_output.put_line('update trigger is chufale .....');

    end;

    /

    运行效果:

    SQL> update student set se='f';

    update trigger is chufale .....

    已更新8行;

    可见,表级触发器在更新了多行的情况下,只触发了一次;

    如果在after update on student后加上

    For each row的话就成为行级触发器,运行效果:

    SQL> update student set se='m';

    update trigger is chufale .....

    update trigger is chufale .....

    update trigger is chufale .....

    update trigger is chufale .....

    update trigger is chufale .....

    update trigger is chufale .....

    update trigger is chufale .....

    update trigger is chufale .....

    已更新8行;

    :new 与: old:必须是针对行级触发器的,也就是说要使用这两个变量的触发器一定有for each row

    这两个变量是系统自动提供的数组变量,:new用来记录新插入的值,old用来记录被删除的值;

    使用insert的时候只有:new里有值;

    使用delete的时候只有:old里有值;

    使用update的时候:new和:old里都有值;

    可以这样使用: dbms_output.put_line('insert trigger is chufa

    dbms_output.put_line('new id is : '||:new.stui

    dbms_output.put_line('new name is : '||:new.st

    dbms_output.put_line('new se is : '||:new.se);

    可以这样从数据字典中查看一个表上有哪几个触发器:

    SQL> select trigger_name from user_triggers

    2 where table_name=upper('student');

    TRIGGER_NAME

    ------------------------------

    TG_INSERT

    TG_UPDATESTUDENT

    带有:old变量的行级delete触发器:

    create or replace trigger tg_deletestudent

    before delete on student

    for each row

    begin

    dbms_output.put_line('old is: '||:old.stuid);

    dbms_output.put_line('old name: '||:old.stuname);

    end;

    /

    运行效果:

    SQL> delete from student;

    old is: 202

    old name: dongqian

    old is: 101

    old name: liudehua

    old is: 102

    old name: lingqingxia

    old is: 103

    old name: lichanggong

    old is: 104

    old name: zhenxiuwen

    old is: 1001

    old name: lilianjie

    old is: 1009

    old name: tongleifuck

    old is: 203

    old name: kfdj

    old is: 209

    old name: fuck

    已删除9行

    When的使用:如果在begin也就是说触发器的PL/SQL主体块执行前加上when(old.se=’f’)的话,DML操作照做不误,但是只会在删除

    Se=’f’的那行的时候才会执行触发器的主体动作,执行效果:

    SQL> delete from student;

    old is: 209

    old name: fuck

    已删除9行; 这里虽然删了9行,但是只执行了一次触发器的主体,做为一个行级触发器;

    混合类型触发器:

    Inserting,deleting,updating三个谓词可以分别指示当前操作到底是哪个;

    create or replace trigger hunhetrigger

    before insert or update or delete on student

    for each row

    begin

    if inserting then

    dbms_output.put_line('insert le.........');

    end if;

    if deleting then

    dbms_output.put_line('delete le .......');

    end if;

    end;

    /

    插入的时候就自动判断当前动作为插入:

    SQL> insert into student values(303,'me','f');

    insert le.........

    删除的时候就自动判断当前动作为删除:

    SQL> delete from student;

    delete le .......

    注意,既然触发器内部的主体PL/SQL是语句,那么它同样也可以是插入删除操作而不一定只是dbms_output打印一些信息;

    这正是日志表的原理:在用户执行了DML语句的时候触发主体为插入日志表以记录操作轨迹的触发器;

    为什么用触发器? 当我们有两个表用来记录商品的出库入库情况,good_store用来记录库存的产品类别和数量,

    而good_out用来记录出库的产品类别和数量,那么每当我们出库的某个类别的产品一定数量的时候,我们应该在good_out中插入该产品的类别和

    出库数量,而同时也应该在good_store表中用update来更新库存的相应类别的产品的数量;这就交给了我们两个必须完成的任务:插入good_out

    表后更新good_store表,这样的手工过程使得我们觉得非常ugly,如果只做其中一个那造成数据的不一致;所以现在我们可以用触发器,在

    Good_out表的插入操作上绑定一个对good_store进行更新的触发器;当然这个过程应该是一个事务,你不必担心插入good_out表执行了,而绑定在这个动作上的触发器操作不会执行,相信Oracle设计为原子性了;

    注意:触发器会使得原来的SQL语句速度变慢;

    替代触发器:

    创建在视图上的触发器,就是替代触发器,只能是行级触发器;

    为什么要用替代触发器?

    假如你有一个视图是基于多个表的字段连接查询得到的;现在如果你想直接对着这个视图insert;那你一定在想,我对视图的插入操作

    怎么来反应到组成这个视图的各个表中呢?事实上,除了定义一个触发器来绑定在对视图上的插入动作上外,你没有别的办法通过系统的报错而直接向视图中插入数据;这就是我们用替代触发器的原因;替换的意思实际上是触发器的主体部分把对视图的插入操作转换成详细的对各个表的插入;

    变异表:变异表就是当前SQL语句正在修改的表,所以在一个变异表上绑定的触发器不可以使用cout()函数,原因很简单:SQL语句刚刚修改了表,你怎么统计??

    约束表:

    维护:

    Alter trigger …..disenable;    使得触发器不可用;

    Alter trigger ……enable;     开启触发器;

    Oracle的内置程序包

    扩展数据库的功能;

    为PL/SQL提供对SQL功能的访问;

    一般具有sys权限的高级管理人员使用;

    一个典型的程序包就是dbms_output,你老是用它的过程put_line();

    Dbms_standard 提供语言工具;

    Dbms_lob操作Oracle LOB;就是针对大型数据的操作设计的;

    Dbms_lock用户定义的锁;

    Dbms_job 允许对PL/SQL过程进行调度;

    Dbms_alert 支持数据库事件的异步通知;

    1,dbms_output的一些过程:

    a):enable

    b):disable

    c):put只是把数据放到缓存(SQL-Plus的缓存,实际就是整个窗口)中,无输出功能;

    d):put_line可以使得以前放在缓存中所有数据输出;并且换到下一行;

    e):new_line

    f):get_line

    g):get_lines

    2,dmbs_lob   ,这个包只能是由系统管理员来操作;

    Clob以字符数据存储可达2G;

    Blob以二进制数据存储可达4G;

    Nclob以unicode字符存储;

    一个文件下载列表的例子:

    创建下载目录表:

    create table downfilelist

    (

    id varchar(20) not null primary key,

    name varchar(40) not null,

    filelocation bfile,

    description clob

    )

    /

    创建目录:

    create or replace directory filedir as 'f:\oracle'

    /只是向Oralce注册了目录,实际上并不会真的建立目录在磁盘上;Oracle无权管理和锁定操作系统的文件系统;

    向目录表中插入数据:

    insert into downfilelist

    values('10001','oracle plsal编程指南',bfilename(upper('filedir'),'demo.mp3'),'this is a mp3 music')

    insert into downfilelist

    values('10002','java 大权', bfilename(upper('filedir'),'x.jpg'),'good super girl')

    /在filedir的目录f:\oracle下实际存储着demo.mp3 ,x.jpg;

    注意,如果你试图查询,效果是 :

    sys>select * from downfilelist;

    SP2-0678: 列或属性类型无法通过 SQL*Plus 显示

    因为第三列是无法显示的,是一个二进制的;

    下面使用dbms_lob的一些过程来进行操作:

    1,read过程

    declare

    tempdesc clob;

    ireadcount int;

    istart int;

    soutputdesc varchar(100);

    begin

    ireadcount:=5;

    istart:=1;

    select description into tempdesc from downfilelist where id='10001';

    dbms_lob.read(tempdesc,ireadcount,istart,soutputdesc); 把clob类型的tempdesc中的数据读到字符类型的soutputdesc里;

    dbms_output.put_line('Top 5 character is: '||soutputdesc);

    end;

    /注意,对unicode来说,汉字和字母所占的位数是一样的;

    2,getlength函数

    select description into tempclob from downfilelist where id=‘10001’;

    ilen:=dbms_lob.GetLength(tempclob);

    append,copy……..

    发现这样的现象:select x into y的时候,y并不是独立于x的拷贝,因为当修改y的时候x也被修改了;

    3, fileexists函数

    select id ,dbms_lob.fileexists(filelocation) from downfilelist;

    如果在bfile类型字段filelocation指定的系统下的目录中存在filelocation指定的系统文件,则返回int 1,否则返回0;

    这说明Oracle还是可以检测到系统的文件情况的,如同java.io包里的类一样;

    对bfile类型数据的操作函数有fileisopen,fileopen,fileclose等等;

    ◆◆

    评论读取中....

    请登录后再发表评论!

    ◆◆

    修改失败,请稍后尝试

    展开全文
  • 触发器 触发器(trigger)是用户定义在关系表上的类由事件驱动的特殊过程。一旦定义,触发器将被保存在数据库服务器中。任何用户对表的增删改操作均由服务器自动激活相应的触发器触发器可以实施更为复杂的...
    本篇总结今日课堂内容,包括触发器、存储过程与函数部分,第5章内容彻底结束。
    一、触发器

    触发器(trigger)是用户定义在关系表上的一类由事件驱动的特殊过程。一旦定义,触发器将被保存在数据库服务器中。任何用户对表的增删改操作均由服务器自动激活相应的触发器。触发器可以实施更为复杂的检查和操作,具有更精细和更强大的数据控制能力。

    1.定义触发器

    触发器又叫做事件-条件-动作规则。当特定事件发生时,对规则的条件进行检查:条件成立则执行规则中的动作,否则不执行。规则中的动作体通常是一段SQL存储过程。
    一般格式如下:

    CREATE TRIGGER <触发器名> – 触发事件发生时,该触发器就被激活
    {BEFORE | AFTER} <触发事件> ON <表名> – 指明触发器激活的时间是在执行触发事件前或后
    REFERENCING NEW|OLD ROW AS<变量> – 指出引用的变量
    FOR EACH {ROW | STATEMENT} – 定义触发器的类型,指明动作体执行的频率
    [WHEN <触发条件>]<触发动作体> – 仅当触发条件为真时才执行触发动作

    触发事件
    触发事件可以是INSERT、DELETE或UPDATE,也可以是这几个事件的组合,还可以UPDATE OF<触发列,…>,即进一步指明修改哪些列时激活触发器

    AFTER/BEFORE是触发的时机
    AFTER表示在触发事件的操作执行之后激活触发器
    BEFORE表示在触发事件的操作执行之前激活触发器

    触发器类型
    行级触发器(FOR EACH ROW)
    语句级触发器(FOR EACH STATEMENT)

    例如,在例5.11的TEACHER表上创建一个AFTER UPDATE触发器,触发事件是UPDATE语句:UPDATE TEACHER SET Deptno=5;假设表TEACHER有1000行,如果是语句级触发器,那么执行完该语句后,触发动作只发生1次(就一个SQL语句)。如果是行级触发器,触发动作将执行1000次(每一行都会触发一次)

    例:当对表SC的Grade属性进行修改时,若分数增加了10%,则将此次操作记录到另一个表SC_U(Sno,Cno,Oldgrade,Newgrade)中,其中Oldgrade是修改前的分数,Newgrade是修改后的分数。

    首先要创建SC_U表
    create table SC_U (
    	Sno char(9),
    	Cno char(4),
    	Oldgrade smallint,  /*因为SC表中Grade数据类型为SMALLINT,所以这里与其相同设置*/
    	Newgrade smallint
    );
    
    定义触发器
    create trigger SC_T
    after update of Grade on SC
    referencing
     oldrow as OldTuple,
     newrow as NewTuple
    for each row
    when(NewTuple.Grade>=1.1*OldTuple.Grade)
    	insert into SC_U(Sno,Cno,OldGrade,NewGrade)
    	values(OldTuple.Sno,OldTuple.Cno,OldTuple.Grade,NewTuple.Grade);
    

    报错,提示
    在这里插入图片描述
    百度搜索,发现了上届一个学长(我还认识他。。)的博客,写的很详细,这里我就借来用了

    吐血整理】数据库的完整性

    T-SQL可创建 DML、DDL 或登录触发器(分为三种)

    触发器是一种特殊类型的存储过程,在数据库服务器中发生事件时自动运行。
    ① 如果用户尝试通过数据操作语言 (DML) 事件修改数据,DML 触发器运行。 DML 事件是针对表或视图的 INSERTUPDATEDELETE 语句。 此类触发器在任何有效事件触发时触发,无论表行是否受影响。
    ② DDL 触发器是为了响应各种数据定义语言 (DDL) 事件而运行。 这些事件主要对应于 Transact-SQL CREATEALTERDROP 语句,以及执行类似 DDL 操作的某些系统存储过程。
    ③ 登录触发器是为了响应在建立用户会话时触发的 LOGON 事件而触发。
    可以直接使用 Transact-SQL 语句创建触发器,也可以使用程序集方法,可以为任何特定语句创建多个触发器。
    — — — — — — — — — — — — — — — — — — — — —
    该例题中涉及的是DML事件,所以应创建DML触发器,可使用SSMS和T-SQL两种办法来创建

    采用T-SQL方式,注意T-SQL中声明变量的时候一定要加@符号,类似于数学模型matlab中的句柄

    deleted 和 inserted 表保存了可能会被用户更改的行的旧值或新值。
    create trigger SC_T
    on SC
    for update
    as             /*声明变量*/
    	declare @OLD smallint
    	declare @NEW smallint
    	declare @SNO char(9)
    	declare @CNO char(4)
    if(update(Grade))
    begin
    	select @OLD = Grade from deleted
    	select @NEW = Grade from inserted
    	select @SNO = Sno from deleted
    	select @CNO = Cno from deleted
    	if(@NEW >= 1.1 * @OLD)
    	insert into SC_U(Sno, Cno, Oldgrade, Newgrade)
    	values (@SNO, @CNO, @OLD, @NEW)
    end;
    
    查看结果,由于是对基本表SC建立的触发器,所以是表触发器,查看方式如下(建议刷新一下,不然缓存等原因无法直接实现,不像idea自动更新和保存)

    在这里插入图片描述

    点击SC_T旁边的小图标还可以发现我们之前写的语句,也就是定义触发器时的语句

    在这里插入图片描述

    下面来测试一下

    SC表的本来面目

    在这里插入图片描述

    update SC
    set Grade = 90
    where Sno='201215121' and Cno='1';
    
    update SC
    set Grade = 98
    WHERE Sno='201215121' and Cno='2';
    
    select * from SC;
    select * from SC_U;
    
    

    在这里插入图片描述

    说明执行成功,针对第一条修改,由于不满足触发器的执行条件(新的成绩大于等于旧成绩的1.1倍),所以并未触发触发器,没有进入,而第二条修改语句满足条件,所以在SC_U表有记录!

    例2:将每次对表Student的插入操作所增加的学生个数记录到StudentInsertLog中

    -- 新建一个StudentInsertLog存储学生人数
    create table StudentInsertLog (
    	Numbers int
    )
    -- 新建表存储用户名和操作时间
    create table StudentInsertLogUser (
    	UserName nchar(10),
    	DateAndTime datetime
    )
    -- 新建触发器Student_Count
    create trigger Student_Count
    after insert on Student  
    referencing
    new table as DELTA
    for each statement  
    insert into StudentInsertLog(Numbers)
    select count(*) from DELTA;-- 查询有多少条数据
    

    PS:不能同时执行所有语句,会报错。应该分开执行,先建立表。
    在这里插入图片描述

    同上一个例子,执行定义触发器部分的命令会报错,更改为T-SQL标准格式下的语句,如下。参考老师博客的链接

    【Transact-SQL】教材 [例5.22] “触发器”(TRIGGER)

    -- Student_Count触发器,
    -- 当插入新的学生记录时,触发器启动,自动在StudentInsertLog记录学生人数
    create trigger Student_Count
    on Student  	         
    after
    insert
    as 
        insert into StudentInsertLog(Numbers)
    	select count(*) from Student;
    
    -- Student_Time触发器
    -- 当插入新的学生记录时,触发器启动,自动在StudentInsertLogUser记录用户名和操作时间
    create trigger Student_Time
    on Student
    after
    insert
    as 
    	declare @UserName nchar(10)
    	declare @DateTime datetime
    
    	select @UserName = system_user
    	select @DateTime = convert(datetime,getdate(),120)
    
    	insert into StudentInsertLogUser(UserName,DateAndTime)
    	values(@UserName,@DateTime);
    
    下面进行测试
    select * from Student; -- 查看插入之前的Student表中的数据内容
    
    insert into Student -- 插入一条数据
    values('201215135','王五','男',18,'CS');
    -- 查询
    select * from Student;
    select * from StudentInsertLog;
    select * from StudentInsertLogUser;
    

    在这里插入图片描述

    == 例3:定义一个before行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”==

    首先要建立Teacher表,这里该表的建立我参考了第5章5.4用户自定义完整性中的例子
    create table Teacher
    (Eno numeric(4) primary key, -- 教职工ID
     Ename char(10), -- 姓名
     Job char(8), -- 具体工作
     Sal numeric(7,2), -- 工资
     Deduct numeric(7,2), -- 扣除费用
     Deptno numeric(2), -- 部门编号
    );
    

    插入一些数据,最终如下

    在这里插入图片描述

    -- 标准SQL
    create trigger Insert_Or_Update_Sal 
    before insert or update on Teacher   /*触发事件是插入或更新操作*/
    for each row        /*行级触发器*/
    begin                    /*定义触发动作体,是PL/SQL过程块*/
    	if (new.Job = '教授') and (new.Sal < 4000) 
    	then  new.Sal := 4000;
    	end if;
    end;
    
    仍然是会出错的,下面是T-SQL中的写法,我喜欢先declare
    create trigger Insert_Or_Update_Sal
    on Teacher
    for update,insert
    as
    	declare @JOB char(9)
    	declare @SAL smallint
    
    if update(Sal)
    begin	
    	select @SAL = Sal from inserted
    	select @JOB = Job from Teacher
    	if(@SAL < 4000 and @JOB = '教授')
    	update Teacher
    	set SAL = 4000
    	where Sal < 4000 and Job = '教授'
    end;
    
    下面进行测试,插入一条数据
    insert into Teacher
    values(1004,'小王','教授',3600,0,4);
    

    在这里插入图片描述

    成功!因为小王是教授,插入的值本来是3600,小于4000,满足触发器激活的条件,所以他的Sal变成了4000。
    2.激活触发器

    触发器的执行,是由触发事件激活的,并由数据库服务器自动执行!
    一个数据表上可能定义了多个触发器,遵循如下的执行顺序:
    (1) 执行该表上的BEFORE触发器;
    (2) 激活触发器的SQL语句;
    (3) 执行该表上的AFTER触发器。

    3.删除触发器

    语法如下:

    DROP TRIGGER<触发器名> ON <表名>

    该触发器必须是一个已经创建的触发器,并且只能由具有相应权限的用户删除。

    例:删除Insert_Or_Update_Sal触发器

    drop trigger Insert_Or_Update_Sal on Teacher;
    

    报错,如下:
    在这里插入图片描述
    在T-SQL中是不能这样写的,参考官方文档和老师上课讲的:官方文档

    drop trigger Insert_Or_Update_Sal;
    -- 或者这样写,下面这种写法更好,类似删表,如果存在才删除
    if(object_id('Insert_Or_Update_Sal') is not null)
    	drop trigger Insert_Or_Update_Sal;
    
    出现以下语句说明删除成功!
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210419133808306.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg0NTAzOQ==,size_16,color_FFFFFF,t_70#pic_center)
    二、存储过程和函数

    这一章本来是第8章,由于和本节相关,所以老师放在一起讲了,因此例题也就都放在了第5章里。

    引入
    过程化SQL块主要有两种类型,即命名块和匿名块,之前学的都是匿名块,匿名块每次执行时都要进行编译,它不能被存储到数据库中,也不能在其他过程化SQL块中调用。过程和函数是命名块,它们被编译后保存在数据库中,称为持久性存储模块,可以被反复调用,运行速度较快。

    存储过程
    1.概念及优点

    存储过程:由过程化SQL语句,经编译和优化后存储在数据库服务器中,可以被反复调用,运行速度较快。

    优点:
    (1)运行效率高
    (2)降低了客户机和服务器之间的通信量
    (3)方便实施企业规则

    2.存储过程的用户接口
    (1)创建存储过程

    CREATE OR REPLACE PROCEDURE 过程名([参数1,参数2,…])
    AS <过程化SQL块>;

    例:利用存储过程来实现下面的应用:从账户1转指定数额的款项到账户2中。

    ①首先要有账户表Account,建立并插入两条数据

    drop table if exists Account;
    
    create table Account(
    	accountnum char(3),-- 编号
    	total float -- 余额
    );
    
    insert into Account
    values('101',50),('102',100);
    
    select * from Account;
    

    在这里插入图片描述
    ②创建存储过程,具有健壮性

    if (exists (select * from sys.objects where name = 'Proc_TRANSFER'))
        drop procedure Proc_TRANSFER
    go
    create procedure Proc_TRANSFER 
    @inAccount int,@outAccount int,@amount float
     /*定义存储过程TRANSFER,参数为转入账户、转出账户、转账额度*/
    as
    begin transaction TRANS   
       	declare	/*定义变量*/
    	@totalDepositOut float,
    	@totalDepositIn float,
    	@inAccountnum int;
    	 /*检查转出账户的余额 */     
    	select @totalDepositOut = total from Account where accountnum = @outAccount;
    	/*如果转出账户不存在或账户中没有存款*/
    	if @totalDepositOut is null               	   
    		begin
    			print '转出账户不存在或账户中没有存款'
    			rollback transaction TRANS; 	   /*回滚事务*/
    			return;
    		end;
    	/*如果账户存款不足*/
    	if @totalDepositOut < @amount     	
    		begin
    			print '账户存款不足'
    			rollback transaction TRANS; 				/*回滚事务*/
    			return;
    		end
    	/*检查转入账户的状态 */  
    	select @inAccountnum = accountnum  from Account	where accountnum = @inAccount;
    	/*如果转入账户不存在*/ 
    	if @inAccountnum is null   		                       
    		begin
    			print '转入账户不存在'
    		    rollback transaction TRANS; 	         	 		/*回滚事务*/
    			return;
    		end;
    	/*如果条件都没有异常,开始转账。*/ 
    	begin
    		update Account set total = total - @amount where accountnum = @outAccount; /* 修改转出账户余额,减去转出额 */
    		update Account set total = total + @amount where accountnum = @inAccount; /* 修改转入账户余额,增加转入额 */
    		print '转账完成,请取走银行卡'
    		commit transaction TRANS;                       	/* 提交转账事务 */
    		return;
    	end
    

    此时查看存储过程的方式和触发器是不同的,前边的触发器都是基于基本表的,而存储过程是基于数据库的,所以应该在当前数据库下寻找。

    在这里插入图片描述

    (2)执行存储过程,T-SQL是用exec,标准SQL是call或者perform

    ①101向102转账50,转完后,101账户余额为0

    select * from Account;
    
    exec Proc_TRANSFER
    	@inAccount = 102, --转入账户
    	@outAccount = 101, --转出账户
    	@amount = 50 --转出金额
    
    select * from Account;
    
    

    在这里插入图片描述
    在这里插入图片描述

    ②101继续向102转账50元,SQL语句同上,此时应该输入账户余额不足
    在这里插入图片描述
    在这里插入图片描述
    ③测试账户不存在

    exec Proc_TRANSFER
    	@inAccount = 110,	--转入账户
    	@outAccount = 102,	--转出账户
    	@amount = 100		--转出金额
    
    select * from Account;
    

    在这里插入图片描述
    测试成功!

    (3)修改存储过程

    ALTER { PROC | PROCEDURE } [schema_name.] procedure_name
    [ { @parameterdata_type } [= ] ] [ ,…n ]
    AS { [ BEGIN ] sql_statement [ ; ] [ ,…n ] [ END ] }
    [;]

    具体操作为:只需将创建存储过程时的create改为alter即可,改动需要改动的地方,其他不变。

    (4)删除存储过程

    drop procedure 过程名;

    例:删除刚刚建立的存储过程

    drop procedure Proc_TRANSFER;
    

    在这里插入图片描述

    3.函数
    函数和存储过程的异同

    同:都是持久性存储模块
    异:函数必须指定返回的类型

    下面是标准SQL函数的相关内容
    1.函数的定义语句格式

    CREATE OR REPLACE FUNCTION 函数名 ([参数1,参数2,…]) RETURNS <类型> AS <过程化SQL块>;

    2.函数的执行语句格式

    CALL/SELECT 函数名 ([参数1,参数2,…]);

    3.修改函数
    重命名

    ALTER FUNCTION 过程名1 RENAME TO 过程名2;

    重新编译

    ALTER FUNCTION 过程名 COMPILE;

    T-SQL标准参考T-SQL中的函数
    例:求男女学生的平均年龄
    ①定义函数

    create function AvgAge(@Sex varchar(10)='男')    --在这里是给参数默认值,即可以不传参数调用这个函数
    returns decimal
    as
    begin
        declare @AvgAge decimal(10,2)
        select @AvgAge=AVG(Convert(decimal(10,2),Sage)) from Student where Ssex=@Sex
        return @AvgAge
    end;
    

    在这里插入图片描述

    ②测试使用

    -- select [函数的所有者].函数名 as 字段别名
     
    select dbo.AvgAge(default) as AvgAge;
    select dbo.AvgAge('男');
    select dbo.AvgAge('女');
    
    这里一定要写函数所有者,默认是dbo,否则会报错!!!

    在这里插入图片描述

    三、课程感悟
    这一部分很难理解,而且理解了,相关的SQL语句也很难编写,感觉没什么规律似的,再加上T-SQL与标准SQL的区别,更是“火上浇油”。不过好在,都找到了解决办法。又结束了一章,老师让写一个这段学习的总结,希望通过总结可以让自己重新记起学过的东西并对它们有更深的理解。加油!

    在这里插入图片描述

    展开全文
  • 什么是mysql触发器需要MySQL 5 对触发器的支持是在MySQL 5中增加的。因此,本章内容适用于MySQL 5或之后的版本。MySQL语句在需要时被执行,存储过程也是...2.每当订购一个产品时,都从库存数量中减去订购的数量;3...
  • 展开全部数据库中触发器before与after认识Before与After区别:before:(insert、update)可以对new进行修改;after不能对new进行修改,两者都e68a84e8a2ad3231313335323631343130323136353331333363386161不能修改old...
  • 分区表自动生成脚本 CREATE FUNCTION "public"."create_table_partition"(IN tablename varchar) ... 这脚本会将前面通过分区脚本创建的分区表中加上相应的触发器,好了,脚本很好理解就不多说了,有问题请留言。
  • 当用到自增序列,需要用到触发器的时候,当我连续执行创建个触发器时,总是报编译通过,但存在警告或错误。---.应用信息drop table app_info cascade constraints;create table APP_INFO(id NUMBER() not null,...
  • 第五章例题

    2021-04-23 13:36:44
    一个数据表上可能定义了多个触发器,遵循如下的执行顺序: (1) 执行该表上的BEFORE触发器; (2) 激活触发器的SQL语句; (3) 执行该表上的AFTER触发器。 5.删除触发器 DROP TRIGGER <触发器名> ON <表名>; 存储...
  • In table A I have fields CENA(price), cena_za_kus(price_per_piece), mnozstvi(quantity).In table B I have field DPH(vat).I'd like to add a before update/insert trigger, which would calculate the value ...
  • after:是先完毕数据的增删改。然后再触发,触发的语句晚于监视的增删改。无法影响前面的增删修改作;也就是说先插入订单记录,再更新商品数量。当商品数量少于订单数量时造成爆库。...#创建触发器test...
  • Oracle DBA Studio 工具里面就能创建触发器CREATE TRIGGER名称CREATE TRIGGER — 创建一个触发器语法CREATE TRIGGER name { BEFORE | AFTER } { event [OR ...] }ON table FOR EACH { ROW | STATEMENT }EXECUTE ...
  • 刚接触Oracle,新建了一个before delete的触发器,但老是报“警告: 创建触发器带有编译错误”,最后发现是触发器里面的语句没有写分号的原因。下面帖出来,也供新手参考:1.创建表:create table test1(CardID ...
  • 创建触发器时,在before和after的选择上,有些区分,下面是一个实例,希望对你有所启发 1、建立一个通信录数据库,要求需要有以下三个表: lxrenb(联系人表)其字段为(联系人编号、姓名、联系电话、家庭地址), ...
  • ,最后发现是触发器里面刚接触Oracle,,新建了一个before delete的触发器,但老是报“警告: 创建触发器带有编译错误”,最后发现是触发器里面的语句没有写分号的原因。下面帖出来,也供新手参考:1.创建表:...
  • 脚本如下-- 1. 创建表-- Create tablecreate table base(id number,descr varchar2(200),create_date date,lst_upd_date date);-- Create/Recreate primary, unique and foreign key constraintsalter t...
  • 一个表的insert的trigger,目的是只修改插入行的字段。CREATE OR REPLACE TRIGGER TR_RME_SLOTBEFORE INSERT ON RME_SLOTFOR EACH ROWBEGINIF (:NEW.POSITION >= 0 AND :NEW.POSITION <10) THEN:NEW.SLOT_...
  • mysql创建触发器问题

    2021-01-27 04:56:44
    你的位置:问答吧->... 问题详情mysql创建触发器问题我想在mysql上创建一个触发器,原代码如下CREATE TRIGGER comment_afterdelete_on_mynewbefore DELETE ON tb1_mynewFOR EACH ROWBEGINselect * from...
  • 示例 1:行级 INSERT 触发器以下触发器一个行级 INSERT 触发器的示例。它检查为新雇员输入的出生日期是否合理:CREATE TRIGGER check_birth_dateAFTER INSERT ON EmployeesREFERENCING NEW AS new_employeeFOR ...
  • 在MySQL中创建触发器通过SQL语句CREATE TRIGGER来实现,其语法形式如下: CREATE trigger trigger_name BEFORE|AFTER trigger_EVENT ON TABLE_NAME FOR EACH ROW trigger_STMT 在上述语句中,参数trigger_name表示要...
  • create or replace trigger drs_asynchronous_trig before insert on drs_asynchronous FOR EACH ROW declare -- local variables here v_trigger_user varchar2(100); v_trigger_date date; v_sqlcode varchar2(6);...
  • MySql 触发器与SQL server 触发器不同:SQL Server 使用inserted、deleted 代表被触发的数据。MySQL NEW代表触发后的新数据行,Old代表当前触发数据被修改前的数据行、Insertdelimiter $$CREATE TRIGGER trigger _...
  • 下面的文章主要描述的是MySQL触发器的正确创建步骤,MySQL触发器的删除,你如果对MySQL触发器的正确创建步骤,MySQL触发器的删除有兴趣的话你就可以点击以下的文章进行观看了。1、创建MySQL触发器:语法:...
  • MySQL中,创建触发器

    2021-03-23 20:19:35
    在MySQL中,创建触发器语法如下: CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt 其中: trigger_name:标识触发器名称,用户自行指定; trigger_time:标识触发...
  • oracle创建与常见问题Oracle DBA Studio 工具里面就能创建触发器CREATE TRIGGER名称CREATE TRIGGER — 创建一个触发器语法CREATE TRIGGER name { BEFORE | AFTER } { event [OR ...] }ON table FOR E...
  • The sql i wrote**delimiter |CREATEDEFINER=CURRENT_USERTRIGGER set_profiletype_after_insert BEFORE INSERT ON trl_translator FOR EACH ROWBEGINUPDATE trl_profile SET trl_profile.type = 'translator' WHERE...
  • 本文主要向大家介绍了MySQL数据库之创建mysql触发器 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助。Summary:inthistutorial,...
  • 触发器一个特殊的存储过程,存储过程是需要手动调用的,而触发器是程序自动出发的,比如在对某张表进行删除操作前执行触发器,可以设置在增删除操作前或者之后执行,下面就创建一个小例子。方...
  • 1.创建触发器 在Mysql中创建触发器通过SQL语句CREATE TRIGGER来实现,其语法形式如下: CREATE trigger trigger_name BEFORE|AFTER trigger_EVENT ontable_name for EACH ORW trigger_STMT 参数trigger_name表示...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,044
精华内容 11,617
关键字:

创建一个before触发器