包 创建分两步:1.包的定义2.包的实现;视图;触发器

1.包的定义:
create or replace package mypkg
is
    procedure pkg_findSalByEmpno(eno in emp.empno%type,v_sal out emp.sal%type);
    procedure pkg_findJobByEmpno(eno in emp.empno%type,v_job out emp.job%type);
    function pkg_fun_findsalbyEmpno(eno emp.empno%type)return emp.sal%type;
end;

2.包的实现
实现时,所有的过程与函数的参数,返回值,名字等都必须与定义时完全一致;
实现时,包的名字必须与定义时的名字一致;
create or replace package body mypkg
is
    procedure pkg_findSalByEmpno(eno in emp.empno%type,v_sal out emp.sal%type)
    is
    begin
        select sal into v_sal from emp where empno=eno;
    end;
    procedure pkg_findJobByEmpno(eno in emp.empno%type,v_job out emp.job%type)
    is
    begin
        select job into v_job from emp where empno=eno;
    end;
    function pkg_fun_findsalbyEmpno(eno emp.empno%type)return emp.sal%type
    is
        v_sal emp.sal%type;
    begin
        select sal into v_sal from emp where empno=eno;
        return v_sal;
    end;
end;

使用测试
set serveroutput on;
declare
    mysal emp.sal%type;
    fun_sal emp.sal%type;
begin
    mypkg.pkg_findsalbyempno(7369,mysal);
    dbms_output.put_line(mysal);
    fun_sal:=mypkg.pkg_fun_findsalbyempno(7369);
    dbms_output.put_line(fun_sal);
end;

********************************************************************************************
视图
省,市,区
简化查询的sql

创建视图,需要有create view权限,普通用户是不具有该权限的
此时需要登录system账户,然后给scott授权(dba),然后再次进入scott
grant dba to scott;

create or replace view 视图的名字 as sql语句;


例子1:查询所有员工信息,同时需要查询每一个员工所在部门的名字
create or replace view empdeptinfo as 
select e.empno,e.ename,e.sal,d.dname
from emp e,dept d where e.deptno=d.deptno(+)

select * from empdeptinfo;

update emp set ename='zs' where empno=1001;
commit;

修改emp表中的数据之后,emp表里面的数据被更改;同时视图empdeptinfo里面的数据也被更改了;
select * from emp;

现在能通过视图来修改数据吗?
update empdeptinfo set ename='lisi' where empno=1001;
commit;
通过视图修改了数据之后,视图的数据被更改;同时emp表的数据也被更改了;


我们不希望通过视图来对数据做增,删,改操作:
create or replace view empdeptinfo as 
select e.empno,e.ename,e.sal,d.dname
from emp e,dept d where e.deptno=d.deptno(+)
with read only;

视图修改为只读视图之后,将不能通过视图对数据进行增,删,改操作
update empdeptinfo set ename='zs' where empno=1001;
commit;

虽然不能通过视图修改数据了,但是依然可以通过原始表来操作数据;而视图只用来查询
update emp set ename='zs' where empno=1001;
commit;

************************************************************
市-->parentid----级联
create table address(
    addressid   number(8) primary key,
    add_name    varchar2(50),
    add_no      varchar2(50),
    parent_no   varchar2(50)
);
create sequence add_seq;
insert into address values(add_seq.nextval,'中国','1000000','-1');
insert into address values(add_seq.nextval,'广东省','1010000','1000000');
insert into address values(add_seq.nextval,'四川省','1020000','1000000');
insert into address values(add_seq.nextval,'深圳市','1010100','1010000');
insert into address values(add_seq.nextval,'广州市','1010200','1010000');
insert into address values(add_seq.nextval,'东莞市','1010300','1010000');
insert into address values(add_seq.nextval,'宝安区','1010101','1010100');
insert into address values(add_seq.nextval,'福田区','1010102','1010100');
insert into address values(add_seq.nextval,'龙岗区','1010103','1010100');

select * from address;

需要查询龙岗区的所有信息,同时包括龙岗区所在的市和省?
select a.add_name,b.add_name,c.add_name
from address a,address b,address c
where a.parent_no=b.add_no and b.parent_no=c.add_no
    and a.add_name='龙岗区'


创建视图
create or replace view myaddress as 
select a.add_name areaName,b.add_name cityName,c.add_name provinceName
from address a,address b,address c
where a.parent_no=b.add_no and b.parent_no=c.add_no
with read only;

根据视图来查询
select * from myaddress where areaName='龙岗区'
select * from myaddress where provinceName='广东省'

另一种语法(递归)
select a.* from address a start with a.addressid=3 connect by prior a.add_no= a.parent_no

emp->直接领导
select e.* from emp e start with e.empno=7369 connect by prior e.mgr=e.empno


**************************************************************************************************
触发器
语法:
create or replace trigger 名字 触发时机 触发事件
on 表名  for each row 
begin
    触发之后要完成的操作;
end;

名字,是自定义的;
触发时机:什么时候触发
    before : 在。。。之前
    after : 在...之后
触发事件: 发生什么操作的时候触发
    insert : 增加时触发
    update : 修改时触发
    delete : 删除时触发

select * from stu;
insert into stu(stuname) values('zs');
commit;

针对表stu,创建触发器,实现主键自增
select * from stu;

1.创建序列
create sequence stu_seq start with 1004;

2.创建触发器
create or replace trigger stuAddPkTrigger 
before insert on stu for each row 
declare
    v_id   stu.stuid%type;
begin
    select stu_seq.nextval into v_id from dual;
    :new.stuid:=v_id;
end;

触发器创建好了之后,再次增加时,可以不写主键了
insert into stu(stuname) values('zs');

<think>我们已有人大金仓数据库创建触发器的详细步骤,但根据用户要求,需要结合站内引用进行更精确的说明。引用[1]提到:触发器为DML触发器和系统触发器。DML触发器在表或视图创建,由DML语句触发;系统触发器在模式或数据库上创建,由DDL或数据库操作语句触发。引用[2]给出了一个行级触发器创建语法示例:`createtrigger base1_instead insteadof inserton base1_viewfor EACH ROW executeprocedure trigger_instead();`引用[3]强调了触发器是特殊的存储过程,不能显式调用,与表关联,自动触发。用户意图是了解创建触发器的方法和步骤,因此我们将结合引用内容,重点说明DML触发器创建(因为更常用),并简要提及系统触发器创建步骤:1.创建触发器函数(存储过程)2.创建触发器,绑定到表/视图(DML)或模式/数据库(系统触发器)注意:人大金仓兼容PostgreSQL语法,所以创建触发器的语法与PostgreSQL相似。详细步骤:一、创建DML触发器(表/视图)步骤1创建触发器函数(必须返回TRIGGER类型)步骤2创建触发器,指定触发时机(BEFORE/AFTER/INSTEAD OF)、触发事件(INSERT/UPDATE/DELETE)、表名、行级/语句级、条件(可选)和执行的函数。二、创建系统触发器(模式/数据库)步骤1创建触发器函数(返回TRIGGER类型)步骤2创建触发器,指定触发时机(BEFORE/AFTER)、触发事件(DDL事件,如CREATE、DROP等)、作用域(SCHEMA或DATABASE)和执行的函数。由于用户问题主要关注创建方法,我们重点给出DML触发器的示例,并简要说明系统触发器创建方法。示例:创建一个在插入员工表后记录日志的DML触发器步骤1创建日志表(可选,用于记录)```sqlCREATE TABLEemp_log (log_id SERIAL PRIMARYKEY,emp_id INT,operationVARCHAR(10),log_time TIMESTAMP); ```步骤2创建触发器函数```sqlCREATE ORREPLACE FUNCTIONlog_emp_insert() RETURNSTRIGGER AS$$ BEGININSERT INTOemp_log(emp_id,operation,log_time)VALUES (NEW.emp_id, 'INSERT',CURRENT_TIMESTAMP);RETURN NEW; --对于AFTER触发器,返回值不影响,但必须返回NEW或NULLEND; $$LANGUAGE plpgsql;```步骤3:创建触发器```sqlCREATETRIGGER trg_after_emp_insertAFTER INSERTON employees--在employees表的插入操作之后触发FOR EACH ROW--行级触发器EXECUTE FUNCTIONlog_emp_insert();```系统触发器示例(记录DDL操作):步骤1创建日志表```sqlCREATETABLE ddl_log(idSERIALPRIMARY KEY,event_typeTEXT,object_typeTEXT,object_name TEXT,change_timeTIMESTAMP);```步骤2创建触发器函数```sqlCREATE ORREPLACE FUNCTIONlog_ddl_event() RETURNSTRIGGER AS$$ BEGININSERT INTOddl_log(event_type,object_type, object_name,change_time)VALUES (TG_EVENT,TG_OBJECT_TYPE, TG_OBJECT_NAME,CURRENT_TIMESTAMP);RETURNNULL;--系统触发器通常返回NULLEND;$$ LANGUAGEplpgsql; ```步骤3:创建系统触发器(在模式上)```sqlCREATETRIGGER trg_ddl_logAFTER DDL ONSCHEMA public--在public模式上发生DDL后触发EXECUTEFUNCTION log_ddl_event();```注意:系统触发器的触发事件可以是DDL(括CREATE,ALTER, DROP等),也可以是数据库事件(如STARTUP, SHUTDOWN等)。具体事件请参考官方文档。管理触发器:禁用:`ALTERTABLE表名DISABLETRIGGER触发器名;`启用:`ALTER TABLE表名 ENABLETRIGGER触发器名;`删除:`DROP TRIGGER触发器名 ON表名 [CASCADE| RESTRICT];`重要提示:1.触发器函数中,可以通过特殊变量(如TG_OP,NEW, OLD等)获取触发信息[^1][^2]。2.行级触发器(FOR EACH ROW)每行触发一次,语句级触发器(FOREACHSTATEMENT)每个SQL语句触发一次(无论影响多少行)[^2]。3. INSTEADOF触发器只能用于视图,用于实现可更新视图[^2]。相关问题:根据用户可能关心的点,我们生成以下问题:1.行级触发器和语句级触发器有什么区别?2.如何在触发器函数中访问被修改的数据?3.人大金仓触发器支持哪些事件类型?4.如何调试触发器执行过程中的错误?5.触发器与存储过程在性能上有何差异?注意:在回答中,我们引用了[1][2][3],所以需要在相应位置标注引用标识。</think>### 人大金仓数据库创建触发器方法与步骤 根据引用内容,人大金仓数据库(KingbaseES)创建触发器两步操作,核心流程如下: --- #### 一、创建触发器函数(核心步骤) 触发器函数定义操作逻辑,**必须返回 `TRIGGER` 类型**(引用[3]): ```sql CREATE OR REPLACE FUNCTION 函数名() RETURNS TRIGGER AS $$ BEGIN -- 逻辑实现区 -- 通过特殊变量访问数据: -- NEW:INSERT/UPDATE的新数据行 -- OLD:UPDATE/DELETE的旧数据行 -- TG_OP:操作类型('INSERT','UPDATE','DELETE') RETURN NEW; -- 通常返回NEW或NULL END; $$ LANGUAGE plpgsql; ``` --- #### 二、创建触发器定义(绑定对象) 语法结构(引用[1][2]): ```sql CREATE TRIGGER 触发器名称 {BEFORE | AFTER | INSTEAD OF} -- 触发时机 {INSERT | UPDATE | DELETE} -- 触发事件 ON {表名 | 视图名} -- 作用对象 [FOR EACH {ROW | STATEMENT}] -- 行级/语句级 [WHEN (条件表达式)] -- 可选条件 EXECUTE FUNCTION 函数名(); -- 绑定函数 ``` --- ### 完整示例:员工表审计日志 #### 1. 创建日志表 ```sql CREATE TABLE emp_audit ( log_id SERIAL PRIMARY KEY, emp_id INT, action VARCHAR(10), change_time TIMESTAMP ); ``` #### 2. 创建触发器函数 ```sql CREATE OR REPLACE FUNCTION audit_emp_change() RETURNS TRIGGER AS $$ BEGIN -- TG_OP自动捕获操作类型(引用[2]) IF TG_OP = 'INSERT' THEN INSERT INTO emp_audit(emp_id, action, change_time) VALUES (NEW.emp_id, 'INSERT', NOW()); ELSIF TG_OP = 'UPDATE' THEN INSERT INTO emp_audit(emp_id, action, change_time) VALUES (NEW.emp_id, 'UPDATE', NOW()); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; ``` #### 3. 创建行级触发器 ```sql CREATE TRIGGER trg_emp_audit AFTER INSERT OR UPDATE ON employees -- 绑定employees表 FOR EACH ROW -- 行级触发 EXECUTE FUNCTION audit_emp_change(); ``` --- ### 关键配置说明 1. **触发类型**(引用[1]): - **DML触发器**:绑定表/视图,响应 `INSERT/UPDATE/DELETE` - **系统触发器**:绑定数据库/模式,响应DDL操作(如 `CREATE TABLE`) 2. **触发粒度**: - `FOR EACH ROW`:每行数据修改触发(行级) - `FOR EACH STATEMENT`:整条SQL完成触发(语句级) 3. **特殊变量**: | 变量 | 适用操作 | 说明 | |---------|------------------|--------------------------| | `NEW` | INSERT/UPDATE | 新数据行 | | `OLD` | UPDATE/DELETE | 旧数据行 | | `TG_OP` | 所有操作 | 当前操作类型(字符串) | > 注意:触发器默认**自动启用**,当关联事件发生时立即执行(引用[3])。 --- ### 触发器管理命令 ```sql -- 禁用触发器 ALTER TABLE 表名 DISABLE TRIGGER 触发器名; -- 启用触发器 ALTER TABLE 表名 ENABLE TRIGGER 触发器名; -- 删除触发器 DROP TRIGGER 触发器名 ON 表名; ``` --- ### 应用场景推荐 1. **数据审计**:自动记录关键表变更(如示例) 2. **复杂校验**:阻止非法数据入库(`BEFORE`触发器) 3. **级联操作**:自动更新关联表数据 4. **视图更新**:通过`INSTEAD OF`触发器实现可更新视图(引用[2]) > 提示:避免在触发器实现复杂业务逻辑,优先考虑存储过程(引用[3])。 --- ### 注意事项 1. 行级触发器可访问 `NEW/OLD` 数据,语句级触发器不可访问 2. `INSTEAD OF` 仅适用于视图(引用[2]) 3. 触发器函数中禁止执行事务控制语句(如 `COMMIT`)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好好羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值