关于oracle触发器语法的问题 5C

刚刚上班的实习生 数据库考完试就都还给老师了TAT 求大神指导,不胜感激!

写一个oracle触发器,将源表T的数据同步到目标表NT中(两表结构相同)

要求是,①当表T中的a字段的值变为‘01’触发器开始执行

② 判断目标表中是否存在当前数据,若存在就不用同步了

3个回答

可能他的意思就是让你多看看相关书籍。有时求人不如求己。oracle不会,但是表示支持。楼主加油

ORACLE PL/SQL编程之八:
把触发器说透

本篇主要内容如下:
8.1 触发器类型
8.1.1 DML触发器
8.1.2 替代触发器
8.1.3 系统触发器
8.2 创建触发器
8.2.1 触发器触发次序
8.2.2 创建DML触发器
8.2.3 创建替代(INSTEAD OF)触发器
8.2.3 创建系统事件触发器
8.2.4 系统触发器事件属性
8.2.5 使用触发器谓词
8.2.6 重新编译触发器
8.3 删除和使能触发器
8.4 触发器和数据字典
8.5 数据库触发器的应用举例

触发器是许多关系数据库系统都提供的一项技术。在ORACLE系统里,触发器类似过程和函数,都有声明,执行和异常处理过程的PL/SQL块。
8.1 触发器类型
触发器在数据库里以独立的对象存储,它与存储过程和函数不同的是,存储过程与函数需要用户显示调用才执行,而触发器是由一个事件来启动运行。即触发器是当某个事件发生时自动地隐式运行。并且,触发器不能接收参数。所以运行触发器就叫触发或点火(firing)。ORACLE事件指的是对数据库的表进行的INSERT、UPDATE及DELETE操作或对视图进行类似的操作。ORACLE将触发器的功能扩展到了触发ORACLE,如数据库的启动与关闭等。所以触发器常用来完成由数据库的完整性约束难以完成的复杂业务规则的约束,或用来监视对数据库的各种操作,实现审计的功能。

8.1.1 DML触发器
ORACLE可以在DML语句进行触发,可以在DML操作前或操作后进行触发,并且可以对每个行或语句操作上进行触发。

8.1.2 替代触发器
由于在ORACLE里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。它就是ORACLE 8专门为进行视图操作的一种处理方法。

8.1.3 系统触发器
ORACLE 8i 提供了第三种类型的触发器叫系统触发器。它可以在ORACLE数据库系统的事件中进行触发,如ORACLE系统的启动与关闭等。

触发器组成:
l 触发事件:引起触发器被触发的事件。 例如:DML语句(INSERT, UPDATE, DELETE语句对表或视图执行数据处理操作)、DDL语句(如CREATE、ALTER、DROP语句在数据库中创建、修改、删除模式对象)、数据库系统事件(如系统启动或退出、异常错误)、用户事件(如登录或退出数据库)。
l 触发时间:即该TRIGGER 是在触发事件发生之前(BEFORE)还是之后(AFTER)触发,也就是触发事件和该TRIGGER 的操作顺序。
l 触发操作:即该TRIGGER 被触发之后的目的和意图,正是触发器本身要做的事情。 例如:PL/SQL 块。
l 触发对象:包括表、视图、模式、数据库。只有在这些对象上发生了符合触发条件的触发事件,才会执行触发操作。
l 触发条件:由WHEN子句指定一个逻辑表达式。只有当该表达式的值为TRUE时,遇到触发事件才会自动执行触发器,使其执行触发操作。
l 触发频率:说明触发器内定义的动作被执行的次数。即语句级(STATEMENT)触发器和行级(ROW)触发器。
语句级(STATEMENT)触发器:是指当某触发事件发生时,该触发器只执行一次;
行级(ROW)触发器:是指当某触发事件发生时,对受到该操作影响的每一行数据,触发器都单独执行一次。
编写触发器时,需要注意以下几点:
l 触发器不接受参数。
l 一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。
l 在一个表上的触发器越多,对在该表上的DML操作的性能影响就越大。
l 触发器最大为32KB。若确实需要,可以先建立过程,然后在触发器中用CALL语句进行调用。
l 在触发器的执行部分只能用DML语句(SELECT、INSERT、UPDATE、DELETE),不能使用DDL语句(CREATE、ALTER、DROP)。
l 触发器中不能包含事务控制语句(COMMIT,ROLLBACK,SAVEPOINT)。因为触发器是触发语句的一部分,触发语句被提交、回退时,触发器也被提交、回退了。
l 在触发器主体中调用的任何过程、函数,都不能使用事务控制语句。
l 在触发器主体中不能申明任何Long和blob变量。新值new和旧值old也不能是表中的任何long和blob列。
l 不同类型的触发器(如DML触发器、INSTEAD OF触发器、系统触发器)的语法格式和作用有较大区别。

8.2 创建触发器
创建触发器的一般语法是:

CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;

其中:
BEFORE 和AFTER指出触发器的触发时序分别为前触发和后触发方式,前触发是在执行触发事件之前触发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。
FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操作影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则只能为行触发器。
REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。
WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。
当一个基表被修改( INSERT, UPDATE, DELETE)时要执行的存储过程,执行时根据其所依附的基表改动而自动触发,因此与应用程序无关,用数据库触发器可以保证数据的一致性和完整性。

每张表最多可建立12 种类型的触发器,它们是:
BEFORE INSERT
BEFORE INSERT FOR EACH ROW
AFTER INSERT
AFTER INSERT FOR EACH ROW

BEFORE UPDATE
BEFORE UPDATE FOR EACH ROW
AFTER UPDATE
AFTER UPDATE FOR EACH ROW

BEFORE DELETE
BEFORE DELETE FOR EACH ROW
AFTER DELETE
AFTER DELETE FOR EACH ROW

8.2.1 触发器触发次序
1. 执行 BEFORE语句级触发器;
2. 对与受语句影响的每一行:
l 执行 BEFORE行级触发器
l 执行 DML语句
l 执行 AFTER行级触发器
3. 执行 AFTER语句级触发器

8.2.2 创建DML触发器
触发器名与过程名和包的名字不一样,它是单独的名字空间,因而触发器名可以和表或过程有相同的名字,但在一个模式中触发器名不能相同。

DML触发器的限制
l CREATE TRIGGER语句文本的字符长度不能超过32KB;
l 触发器体内的SELECT 语句只能为SELECT … INTO …结构,或者为定义游标所使用的SELECT 语句。
l 触发器中不能使用数据库事务控制语句 COMMIT; ROLLBACK, SVAEPOINT 语句;
l 由触发器所调用的过程或函数也不能使用数据库事务控制语句;
l 触发器中不能使用LONG, LONG RAW 类型;
l 触发器内可以参照LOB 类型列的列值,但不能通过 :NEW 修改LOB列中的数据;

DML触发器基本要点
l 触发时机:指定触发器的触发时间。如果指定为BEFORE,则表示在执行DML操作之前触发,以便防止某些错误操作发生或实现某些业务规则;如果指定为AFTER,则表示在执行DML操作之后触发,以便记录该操作或做某些事后处理。
l 触发事件:引起触发器被触发的事件,即DML操作(INSERT、UPDATE、DELETE)。既可以是单个触发事件,也可以是多个触发事件的组合(只能使用OR逻辑组合,不能使用AND逻辑组合)。
l 条件谓词:当在触发器中包含多个触发事件(INSERT、UPDATE、DELETE)的组合时,为了分别针对不同的事件进行不同的处理,需要使用ORACLE提供的如下条件谓词。
1)。INSERTING:当触发事件是INSERT时,取值为TRUE,否则为FALSE。
2)。UPDATING [(column_1,column_2,…,column_x)]:当触发事件是UPDATE 时,如果修改了column_x列,则取值为TRUE,否则为FALSE。其中column_x是可选的。
3)。DELETING:当触发事件是DELETE时,则取值为TRUE,否则为FALSE。
解发对象:指定触发器是创建在哪个表、视图上。
l 触发类型:是语句级还是行级触发器。
l 触发条件:由WHEN子句指定一个逻辑表达式,只允许在行级触发器上指定触发条件,指定UPDATING后面的列的列表。

问题:当触发器被触发时,要使用被插入、更新或删除的记录中的列值,有时要使用操作前、 后列的值.
实现: :NEW 修饰符访问操作完成后列的值
:OLD 修饰符访问操作完成前列的值

特性
INSERT
UPDATE
DELETE
OLD
NULL
实际值
实际值
NEW
实际值
实际值
NULL

例1: 建立一个触发器, 当职工表 emp 表被删除一条记录时,把被删除记录写到职工表删除日志表中去。

CREATE TABLE emp_his AS SELECT * FROM EMP WHERE 1=2;
CREATE OR REPLACE TRIGGER tr_del_emp
BEFORE DELETE --指定触发时机为删除操作前触发
ON scott.emp
FOR EACH ROW --说明创建的是行级触发器
BEGIN
--将修改前数据插入到日志记录表 del_emp ,以供监督使用。
INSERT INTO emp_his(deptno , empno, ename , job ,mgr , sal , comm , hiredate )
VALUES( :old.deptno, :old.empno, :old.ename , :old.job,:old.mgr, :old.sal, :old.comm, :old.hiredate );
END;
DELETE emp WHERE empno=7788;
DROP TABLE emp_his;
DROP TRIGGER del_emp;

例2:限制对Departments表修改(包括INSERT,DELETE,UPDATE)的时间范围,即不允许在非工作时间修改departments表。

CREATE OR REPLACE TRIGGER tr_dept_time
BEFORE INSERT OR DELETE OR UPDATE
ON departments
BEGIN
IF (TO_CHAR(sysdate,'DAY') IN ('星期六', '星期日')) OR (TO_CHAR(sysdate, 'HH24:MI') NOT BETWEEN '08:30' AND '18:00') THEN
RAISE_APPLICATION_ERROR(-20001, '不是上班时间,不能修改departments表');
END IF;
END;

例3:限定只对部门号为80的记录进行行触发器操作。

CREATE OR REPLACE TRIGGER tr_emp_sal_comm
BEFORE UPDATE OF salary, commission_pct
OR DELETE
ON HR.employees
FOR EACH ROW
WHEN (old.department_id = 80)
BEGIN
CASE
WHEN UPDATING ('salary') THEN
IF :NEW.salary < :old.salary THEN

       RAISE_APPLICATION_ERROR(-20001, '部门80的人员的工资不能降');
    END IF;
 WHEN UPDATING ('commission_pct') THEN

    IF :NEW.commission_pct < :old.commission_pct THEN
       RAISE_APPLICATION_ERROR(-20002, '部门80的人员的奖金不能降');
    END IF;
 WHEN DELETING THEN
      RAISE_APPLICATION_ERROR(-20003, '不能删除部门80的人员记录');
 END CASE;

END;

/*
实例:
UPDATE employees SET salary = 8000 WHERE employee_id = 177;
DELETE FROM employees WHERE employee_id in (177,170);
*/

例4:利用行触发器实现级联更新。在修改了主表regions中的region_id之后(AFTER),级联的、自动的更新子表countries表中原来在该地区的国家的region_id。

CREATE OR REPLACE TRIGGER tr_reg_cou
AFTER update OF region_id
ON regions
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('旧的region_id值是'||:old.region_id
||'、新的region_id值是'||:new.region_id);
UPDATE countries SET region_id = :new.region_id
WHERE region_id = :old.region_id;
END;
例5:在触发器中调用过程。

CREATE OR REPLACE PROCEDURE add_job_history
( p_emp_id job_history.employee_id%type
, p_start_date job_history.start_date%type
, p_end_date job_history.end_date%type
, p_job_id job_history.job_id%type
, p_department_id job_history.department_id%type
)
IS
BEGIN
INSERT INTO job_history (employee_id, start_date, end_date,
job_id, department_id)
VALUES(p_emp_id, p_start_date, p_end_date, p_job_id, p_department_id);
END add_job_history;

--创建触发器调用存储过程...
CREATE OR REPLACE TRIGGER update_job_history
AFTER UPDATE OF job_id, department_id ON employees
FOR EACH ROW
BEGIN
add_job_history(:old.employee_id, :old.hire_date, sysdate,
:old.job_id, :old.department_id);
END;

8.2.3 创建替代(INSTEAD OF)触发器

创建触发器的一般语法是:

CREATE [OR REPLACE] TRIGGER trigger_name
INSTEAD OF
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.] view_name --只能定义在视图上
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ] --因为INSTEAD OF触发器只能在行级上触发,所以没有必要指定
[WHEN condition]
PL/SQL_block | CALL procedure_name;

其中:
INSTEAD OF 选项使ORACLE激活触发器,而不执行触发事件。只能对视图和对象视图建立INSTEAD OF触发器,而不能对表、模式和数据库建立INSTEAD OF 触发器。
FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操走影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE 和AFTER 触发器为语句触发器,而INSTEAD OF 触发器则为行触发器。
REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。
WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。

INSTEAD_OF 用于对视图的DML触发,由于视图有可能是由多个表进行联结(join)而成,因而并非是所有的联结都是可更新的。但可以按照所需的方式执行更新,例如下面情况:

例1:

CREATE OR REPLACE VIEW emp_view AS
SELECT deptno, count(*) total_employeer, sum(sal) total_salary
FROM emp GROUP BY deptno;

在此视图中直接删除是非法:
SQL>DELETE FROM emp_view WHERE deptno=10;
DELETE FROM emp_view WHERE deptno=10

ERROR 位于第 1 行:
ORA-01732: 此视图的数据操纵操作非法

但是我们可以创建INSTEAD_OF触发器来为 DELETE 操作执行所需的处理,即删除EMP表中所有基准行:

CREATE OR REPLACE TRIGGER emp_view_delete
INSTEAD OF DELETE ON emp_view FOR EACH ROW
BEGIN
DELETE FROM emp WHERE deptno= :old.deptno;
END emp_view_delete;

DELETE FROM emp_view WHERE deptno=10;

DROP TRIGGER emp_view_delete;

DROP VIEW emp_view;

例2:创建复杂视图,针对INSERT操作创建INSTEAD OF触发器,向复杂视图插入数据。
l 创建视图:

CREATE OR REPLACE FORCE VIEW "HR"."V_REG_COU" ("R_ID", "R_NAME", "C_ID", "C_NAME")
AS
SELECT r.region_id,
r.region_name,
c.country_id,
c.country_name
FROM regions r,
countries c
WHERE r.region_id = c.region_id;

l 创建触发器:

CREATE OR REPLACE TRIGGER "HR"."TR_I_O_REG_COU" INSTEAD OF
INSERT ON v_reg_cou FOR EACH ROW DECLARE v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count FROM regions WHERE region_id = :new.r_id;
IF v_count = 0 THEN
INSERT INTO regions
(region_id, region_name
) VALUES
(:new.r_id, :new.r_name
);
END IF;

SELECT COUNT(*) INTO v_count FROM countries WHERE country_id = :new.c_id;
IF v_count = 0 THEN
INSERT
INTO countries
(
country_id,
country_name,
region_id
)
VALUES
(
:new.c_id,
:new.c_name,
:new.r_id
);
END IF;
END;

创建INSTEAD OF触发器需要注意以下几点:
l 只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项。
l 不能指定BEFORE 或 AFTER选项。
l FOR EACH ROW子可是可选的,即INSTEAD OF触发器只能在行级上触发、或只能是行级触发器,没有必要指定。
l 没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。

8.2.3 创建系统事件触发器
ORACLE10G提供的系统事件触发器可以在DDL或数据库系统上被触发。DDL指的是数据定义语言,如CREATE 、ALTER及DROP 等。而数据库系统事件包括数据库服务器的启动或关闭,用户的登录与退出、数据库服务错误等。创建系统触发器的语法如下:
创建触发器的一般语法是:

CREATE OR REPLACE TRIGGER [sachema.]trigger_name
{BEFORE|AFTER}
{ddl_event_list | database_event_list}
ON { DATABASE | [schema.]SCHEMA }
[WHEN condition]
PL/SQL_block | CALL procedure_name;

其中: ddl_event_list:一个或多个DDL 事件,事件间用 OR 分开;
database_event_list:一个或多个数据库事件,事件间用 OR 分开;

       系统事件触发器既可以建立在一个模式上,又可以建立在整个数据库上。当建立在模式(SCHEMA)之上时,只有模式所指定用户的DDL操作和它们所导致的错误才激活触发器, 默认时为当前用户模式。当建立在数据库(DATABASE)之上时,该数据库所有用户的DDL操作和他们所导致的错误,以及数据库的启动和关闭均可激活触发器。要在数据库之上建立触发器时,要求用户具有ADMINISTER DATABASE TRIGGER权限。

下面给出系统触发器的种类和事件出现的时机(前或后):
事件
允许的时机
说明
STARTUP
AFTER
启动数据库实例之后触发
SHUTDOWN
BEFORE
关闭数据库实例之前触发(非正常关闭不触发)
SERVERERROR
AFTER
数据库服务器发生错误之后触发
LOGON
AFTER
成功登录连接到数据库后触发
LOGOFF
BEFORE
开始断开数据库连接之前触发
CREATE
BEFORE,AFTER
在执行CREATE语句创建数据库对象之前、之后触发
DROP
BEFORE,AFTER
在执行DROP语句删除数据库对象之前、之后触发
ALTER
BEFORE,AFTER
在执行ALTER语句更新数据库对象之前、之后触发
DDL
BEFORE,AFTER
在执行大多数DDL语句之前、之后触发
GRANT
BEFORE,AFTER
执行GRANT语句授予权限之前、之后触发
REVOKE
BEFORE,AFTER
执行REVOKE语句收权限之前、之后触犯发
RENAME
BEFORE,AFTER
执行RENAME语句更改数据库对象名称之前、之后触犯发
AUDIT / NOAUDIT
BEFORE,AFTER
执行AUDIT或NOAUDIT进行审计或停止审计之前、之后触发

8.2.4 系统触发器事件属性

事件属性\事件
Startup/Shutdown
Servererror
Logon/Logoff
DDL
DML
事件名称
ü*
ü*
ü*
ü*

数据库名称
ü*

数据库实例号
ü*

错误号

ü*

用户名

ü*

模式对象类型

ü*

模式对象名称

ü*

ü*

除DML语句的列属性外,其余事件属性值可通过调用ORACLE定义的事件属性函数来读取。
函数名称
数据类型
说 明
Ora_sysevent
VARCHAR2(20)
激活触发器的事件名称
Instance_num
NUMBER
数据库实例名
Ora_database_name
VARCHAR2(50)
数据库名称
Server_error(posi)
NUMBER
错误信息栈中posi指定位置中的错误号

Is_servererror(err_number)

BOOLEAN
检查err_number指定的错误号是否在错误信息栈中,如果在则返回TRUE,否则返回FALSE。在触发器内调用此函数可以判断是否发生指定的错误。
Login_user
VARCHAR2(30)
登陆或注销的用户名称
Dictionary_obj_type
VARCHAR2(20)
DDL语句所操作的数据库对象类型
Dictionary_obj_name
VARCHAR2(30)
DDL语句所操作的数据库对象名称
Dictionary_obj_owner
VARCHAR2(30)
DDL语句所操作的数据库对象所有者名称
Des_encrypted_password
VARCHAR2(2)
正在创建或修改的经过DES算法加密的用户口令

例1:创建触发器,存放有关事件信息。
DESC ora_sysevent
DESC ora_login_user

--创建用于记录事件用的表

CREATE TABLE ddl_event
(crt_date timestamp PRIMARY KEY,
event_name VARCHAR2(20),
user_name VARCHAR2(10),
obj_type VARCHAR2(20),
obj_name VARCHAR2(20));

--创建触犯发器
CREATE OR REPLACE TRIGGER tr_ddl
AFTER DDL ON SCHEMA
BEGIN
INSERT INTO ddl_event VALUES
(systimestamp,ora_sysevent, ora_login_user,
ora_dict_obj_type, ora_dict_obj_name);
END tr_ddl;

例2:创建登录、退出触发器。

CREATE TABLE log_event
(user_name VARCHAR2(10),
address VARCHAR2(20),
logon_date timestamp,
logoff_date timestamp);

--创建登录触发器
CREATE OR REPLACE TRIGGER tr_logon
AFTER LOGON ON DATABASE
BEGIN
INSERT INTO log_event (user_name, address, logon_date)
VALUES (ora_login_user, ora_client_ip_address, systimestamp);
END tr_logon;
--创建退出触发器
CREATE OR REPLACE TRIGGER tr_logoff
BEFORE LOGOFF ON DATABASE
BEGIN
INSERT INTO log_event (user_name, address, logoff_date)
VALUES (ora_login_user, ora_client_ip_address, systimestamp);
END tr_logoff;

8.2.5 使用触发器谓词
ORACLE 提供三个参数INSERTING, UPDATING,DELETING 用于判断触发了哪些操作。
谓词
行为
INSERTING
如果触发语句是 INSERT 语句,则为TRUE,否则为FALSE
UPDATING
如果触发语句是 UPDATE语句,则为TRUE,否则为FALSE
DELETING
如果触发语句是 DELETE 语句,则为TRUE,否则为FALSE

8.2.6 重新编译触发器
如果在触发器内调用其它函数或过程,当这些函数或过程被删除或修改后,触发器的状态将被标识为无效。当DML语句激活一个无效触发器时,ORACLE将重新编译触发器代码,如果编译时发现错误,这将导致DML语句执行失败。
在PL/SQL程序中可以调用ALTER TRIGGER语句重新编译已经创建的触发器,格式为:

ALTER TRIGGER [schema.] trigger_name COMPILE [ DEBUG]
其中:DEBUG 选项要器编译器生成PL/SQL 程序条使其所使用的调试代码。
8.3 删除和使能触发器
l 删除触发器:
DROP TRIGGER trigger_name;
当删除其他用户模式中的触发器名称,需要具有DROP ANY TRIGGER系统权限,当删除建立在数据库上的触发器时,用户需要具有ADMINISTER DATABASE TRIGGER系统权限。
此外,当删除表或视图时,建立在这些对象上的触发器也随之删除。
l 禁用或启用触发器
数据库TRIGGER 的状态:
有效状态(ENABLE):当触发事件发生时,处于有效状态的数据库触发器TRIGGER 将被触发。
无效状态(DISABLE):当触发事件发生时,处于无效状态的数据库触发器TRIGGER 将不会被触发,此时就跟没有这个数据库触发器(TRIGGER) 一样。
数据库TRIGGER的这两种状态可以互相转换。格式为:
ALTER TIGGER trigger_name [DISABLE | ENABLE ];

--例:ALTER TRIGGER emp_view_delete DISABLE;

       ALTER TRIGGER语句一次只能改变一个触发器的状态,而ALTER TABLE语句则一次能够改变与指定表相关的所有触发器的使用状态。格式为:             

ALTER TABLE [schema.]table_name {ENABLE|DISABLE} ALL TRIGGERS;

--例:使表EMP 上的所有TRIGGER 失效:
ALTER TABLE emp DISABLE ALL TRIGGERS;

8.4 触发器和数据字典
相关数据字典:USER_TRIGGERS、ALL_TRIGGERS、DBA_TRIGGERS
SELECT TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT,
TABLE_OWNER, BASE_OBJECT_TYPE, REFERENCING_NAMES,
STATUS, ACTION_TYPE
FROM user_triggers;

8.5 数据库触发器的应用举例
例1:创建一个DML语句级触发器,当对emp表执行INSERT, UPDATE, DELETE 操作时,它自动更新dept_summary 表中的数据。由于在PL/SQL块中不能直接调用DDL语句,所以,利用ORACLE内置包DBMS_UTILITY中的EXEC_DDL_STATEMENT过程,由它执行DDL语句创建触发器。

CREATE TABLE dept_summary(
Deptno NUMBER(2),
Sal_sum NUMBER(9, 2),
Emp_count NUMBER);

INSERT INTO dept_summary(deptno, sal_sum, emp_count)
SELECT deptno, SUM(sal), COUNT(*)
FROM emp
GROUP BY deptno;

--创建一个PL/SQL过程disp_dept_summary
--在触发器中调用该过程显示dept_summary标中的数据。
CREATE OR REPLACE PROCEDURE disp_dept_summary
IS
Rec dept_summary%ROWTYPE;
CURSOR c1 IS SELECT * FROM dept_summary;
BEGIN
OPEN c1;
FETCH c1 INTO REC;
DBMS_OUTPUT.PUT_LINE('deptno sal_sum emp_count');
DBMS_OUTPUT.PUT_LINE('-------------------------------------');
WHILE c1%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(RPAD(rec.deptno, 6)||
To_char(rec.sal_sum, '$999,999.99')||
LPAD(rec.emp_count, 13));
FETCH c1 INTO rec;
END LOOP;
CLOSE c1;
END;
BEGIN
DBMS_OUTPUT.PUT_LINE('插入前');
Disp_dept_summary();
DBMS_UTILITY.EXEC_DDL_STATEMENT('
CREATE OR REPLACE TRIGGER trig1
AFTER INSERT OR DELETE OR UPDATE OF sal ON emp
BEGIN
DBMS_OUTPUT.PUT_LINE(''正在执行trig1 触发器…'');
DELETE FROM dept_summary;
INSERT INTO dept_summary(deptno, sal_sum, emp_count)
SELECT deptno, SUM(sal), COUNT(*)
FROM emp GROUP BY deptno;
END;
');

INSERT INTO dept(deptno, dname, loc)
VALUES(90, ‘demo_dept’, ‘none_loc’);
INSERT INTO emp(ename, deptno, empno, sal)
VALUES(USER, 90, 9999, 3000);

DBMS_OUTPUT.PUT_LINE('插入后');
Disp_dept_summary();

UPDATE emp SET sal=1000 WHERE empno=9999;
DBMS_OUTPUT.PUT_LINE('修改后');
Disp_dept_summary();

DELETE FROM emp WHERE empno=9999;
DELETE FROM dept WHERE deptno=90;

DBMS_OUTPUT.PUT_LINE('删除后');
Disp_dept_summary();
DBMS_UTILITY.EXEC_DDL_STATEMENT(‘DROP TRIGGER trig1’);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);

END;

例2:创建DML语句行级触发器。当对emp表执行INSERT, UPDATE, DELETE 操作时,它自动更新dept_summary 表中的数据。由于在PL/SQL块中不能直接调用DDL语句,所以,利用ORACLE内置包DBMS_UTILITY中的EXEC_DDL_STATEMENT过程,由它执行DDL语句创建触发器。

BEGIN
DBMS_OUTPUT.PUT_LINE('插入前');
Disp_dept_summary();
DBMS_UTILITY.EXEC_DDL_STATEMENT(
'CREATE OR REPLACE TRIGGER trig2_update
AFTER UPDATE OF sal ON emp
REFERENCING OLD AS old_emp NEW AS new_emp
FOR EACH ROW
WHEN (old_emp.sal != new_emp.sal)
BEGIN
DBMS_OUTPUT.PUT_LINE(''正在执行trig2_update 触发器…'');
DBMS_OUTPUT.PUT_LINE(''sal 旧值:''|| :old_emp.sal);
DBMS_OUTPUT.PUT_LINE(''sal 新值:''|| :new_emp.sal);
UPDATE dept_summary
SET sal_sum=sal_sum + :new_emp.sal - :old_emp.sal
WHERE deptno = :new_emp.deptno;
END;'
);

DBMS_UTILITY.EXEC_DDL_STATEMENT(
'CREATE OR REPLACE TRIGGER trig2_insert
AFTER INSERT ON emp
REFERENCING NEW AS new_emp
FOR EACH ROW
DECLARE
I NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE(''正在执行trig2_insert 触发器…'');
SELECT COUNT(*) INTO I
FROM dept_summary WHERE deptno = :new_emp.deptno;
IF I > 0 THEN
UPDATE dept_summary
SET sal_sum=sal_sum+:new_emp.sal,
Emp_count=emp_count+1
WHERE deptno = :new_emp.deptno;
ELSE
INSERT INTO dept_summary
VALUES (:new_emp.deptno, :new_emp.sal, 1);
END IF;
END;'
);

DBMS_UTILITY.EXEC_DDL_STATEMENT(
'CREATE OR REPLACE TRIGGER trig2_delete
AFTER DELETE ON emp
REFERENCING OLD AS old_emp
FOR EACH ROW
DECLARE
I NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE(''正在执行trig2_delete 触发器…'');
SELECT emp_count INTO I
FROM dept_summary WHERE deptno = :old_emp.deptno;
IF I >1 THEN
UPDATE dept_summary
SET sal_sum=sal_sum - :old_emp.sal,
Emp_count=emp_count - 1
WHERE deptno = :old_emp.deptno;
ELSE
DELETE FROM dept_summary WHERE deptno = :old_emp.deptno;
END IF;
END;'
);

INSERT INTO dept(deptno, dname, loc)
VALUES(90, 'demo_dept', 'none_loc');
INSERT INTO emp(ename, deptno, empno, sal)
VALUES(USER, 90, 9999, 3000);
INSERT INTO emp(ename, deptno, empno, sal)
VALUES(USER, 90, 9998, 2000);
DBMS_OUTPUT.PUT_LINE('插入后');
Disp_dept_summary();

UPDATE emp SET sal = sal*1.1 WHERE deptno=90;
DBMS_OUTPUT.PUT_LINE('修改后');
Disp_dept_summary();

DELETE FROM emp WHERE deptno=90;
DELETE FROM dept WHERE deptno=90;
DBMS_OUTPUT.PUT_LINE('删除后');
Disp_dept_summary();

DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2_update');
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2_insert');
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2_delete');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;

例3:利用ORACLE提供的条件谓词INSERTING、UPDATING和DELETING创建与例2具有相同功能的触发器。

BEGIN
DBMS_OUTPUT.PUT_LINE('插入前');
Disp_dept_summary();
DBMS_UTILITY.EXEC_DDL_STATEMENT(
'CREATE OR REPLACE TRIGGER trig2
AFTER INSERT OR DELETE OR UPDATE OF sal
ON emp
REFERENCING OLD AS old_emp NEW AS new_emp
FOR EACH ROW
DECLARE
I NUMBER;
BEGIN
IF UPDATING AND :old_emp.sal != :new_emp.sal THEN
DBMS_OUTPUT.PUT_LINE(''正在执行trig2 触发器…'');
DBMS_OUTPUT.PUT_LINE(''sal 旧值:''|| :old_emp.sal);
DBMS_OUTPUT.PUT_LINE(''sal 新值:''|| :new_emp.sal);
UPDATE dept_summary
SET sal_sum=sal_sum + :new_emp.sal - :old_emp.sal
WHERE deptno = :new_emp.deptno;
ELSIF INSERTING THEN
DBMS_OUTPUT.PUT_LINE(''正在执行trig2触发器…'');
SELECT COUNT(*) INTO I
FROM dept_summary
WHERE deptno = :new_emp.deptno;
IF I > 0 THEN
UPDATE dept_summary
SET sal_sum=sal_sum+:new_emp.sal,
Emp_count=emp_count+1
WHERE deptno = :new_emp.deptno;
ELSE
INSERT INTO dept_summary
VALUES (:new_emp.deptno, :new_emp.sal, 1);
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE(''正在执行trig2触发器…'');
SELECT emp_count INTO I
FROM dept_summary WHERE deptno = :old_emp.deptno;
IF I > 1 THEN
UPDATE dept_summary
SET sal_sum=sal_sum - :old_emp.sal,
Emp_count=emp_count - 1
WHERE deptno = :old_emp.deptno;
ELSE
DELETE FROM dept_summary
WHERE deptno = :old_emp.deptno;
END IF;
END IF;
END;'
);

INSERT INTO dept(deptno, dname, loc)
VALUES(90, 'demo_dept', 'none_loc');
INSERT INTO emp(ename, deptno, empno, sal)
VALUES(USER, 90, 9999, 3000);
INSERT INTO emp(ename, deptno, empno, sal)
VALUES(USER, 90, 9998, 2000);
DBMS_OUTPUT.PUT_LINE('插入后');
Disp_dept_summary();

UPDATE emp SET sal = sal*1.1 WHERE deptno=90;
DBMS_OUTPUT.PUT_LINE('修改后');
Disp_dept_summary();

DELETE FROM emp WHERE deptno=90;
DELETE FROM dept WHERE deptno=90;
DBMS_OUTPUT.PUT_LINE('删除后');
Disp_dept_summary();

DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;

例4:创建INSTEAD OF 触发器。首先创建一个视图myview,由于该视图是复合查询所产生的视图,所以不能执行DML语句。根据用户对视图所插入的数据判断需要将数据插入到哪个视图基表中,然后对该基表执行插入操作。

DECLARE
No NUMBER;
Name VARCHAR2(20);
BEGIN
DBMS_UTILITY.EXEC_DDL_STATEMENT('
CREATE OR REPLACE VIEW myview AS
SELECT empno, ename, ''E'' type FROM emp
UNION
SELECT dept.deptno, dname, ''D'' FROM dept
');
-- 创建INSTEAD OF 触发器trigger3;
DBMS_UTILITY.EXEC_DDL_STATEMENT('
CREATE OR REPLACE TRIGGER trig3
INSTEAD OF INSERT ON myview
REFERENCING NEW n
FOR EACH ROW
DECLARE
Rows INTEGER;
BEGIN
DBMS_OUTPUT.PUT_LINE(''正在执行trig3触发器…'');
IF :n.type = ''D'' THEN
SELECT COUNT(*) INTO rows
FROM dept WHERE deptno = :n.empno;
IF rows = 0 THEN
DBMS_OUTPUT.PUT_LINE(''向dept表中插入数据…'');
INSERT INTO dept(deptno, dname, loc)
VALUES (:n.empno, :n.ename, ''none’’);
ELSE
DBMS_OUTPUT.PUT_LINE(''编号为''|| :n.empno||
''的部门已存在,插入操作失败!'');
END IF;
ELSE
SELECT COUNT(*) INTO rows
FROM emp WHERE empno = :n.empno;
IF rows = 0 THEN
DBMS_OUTPUT.PUT_LINE('’向emp表中插入数据…’’);
INSERT INTO emp(empno, ename)
VALUES(:n.empno, :n.ename);
ELSE
DBMS_OUTPUT.PUT_LINE(''编号为''|| :n.empno||
''的人员已存在,插入操作失败!'');
END IF;
END IF;
END;
');

INSERT INTO myview VALUES (70, 'demo', 'D');
INSERT INTO myview VALUES (9999, USER, 'E');
SELECT deptno, dname INTO no, name FROM dept WHERE deptno=70;
DBMS_OUTPUT.PUT_LINE('员工编号:'||TO_CHAR(no)||'姓名:'||name);
SELECT empno, ename INTO no, name FROM emp WHERE empno=9999;
DBMS_OUTPUT.PUT_LINE('部门编号:'||TO_CHAR(no)||'姓名:'||name);

DELETE FROM emp WHERE empno=9999;
DELETE FROM dept WHERE deptno=70;
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig3');
END;

例5:利用ORACLE事件属性函数,创建一个系统事件触发器。首先创建一个事件日志表eventlog,由它存储用户在当前数据库中所创建的数据库对象,以及用户的登陆和注销、数据库的启动和关闭等事件,之后创建trig4_ddl、trig4_before和trig4_after触发器,它们调用事件属性函数将各个事件记录到eventlog数据表中。

BEGIN
-- 创建用于记录事件日志的数据表
DBMS_UTILITY.EXEC_DDL_STATEMENT('
CREATE TABLE eventlog(
Eventname VARCHAR2(20) NOT NULL,
Eventdate date default sysdate,
Inst_num NUMBER NULL,
Db_name VARCHAR2(50) NULL,
Srv_error NUMBER NULL,
Username VARCHAR2(30) NULL,
Obj_type VARCHAR2(20) NULL,
Obj_name VARCHAR2(30) NULL,
Obj_owner VARCHAR2(30) NULL
)
');

-- 创建DDL触发器trig4_ddl
DBMS_UTILITY.EXEC_DDL_STATEMENT('
    CREATE OR REPLACE TRIGGER trig4_ddl
        AFTER CREATE OR ALTER OR DROP 

ON DATABASE
DECLARE
Event VARCHAR2(20);
Typ VARCHAR2(20);
Name VARCHAR2(30);
Owner VARCHAR2(30);
BEGIN
-- 读取DDL事件属性
Event := SYSEVENT;
Typ := DICTIONARY_OBJ_TYPE;
Name := DICTIONARY_OBJ_NAME;
Owner := DICTIONARY_OBJ_OWNER;
--将事件属性插入到事件日志表中
INSERT INTO scott.eventlog(eventname, obj_type, obj_name, obj_owner)
VALUES(event, typ, name, owner);
END;
');

-- 创建LOGON、STARTUP和SERVERERROR 事件触发器
DBMS_UTILITY.EXEC_DDL_STATEMENT('
    CREATE OR REPLACE TRIGGER trig4_after
        AFTER LOGON OR STARTUP OR SERVERERROR 
  ON DATABASE
    DECLARE
        Event VARCHAR2(20);
        Instance NUMBER;
        Err_num NUMBER;
        Dbname VARCHAR2(50);
        User VARCHAR2(30);
    BEGIN
        Event := SYSEVENT;
        IF event = ''LOGON'' THEN
            User := LOGIN_USER;
            INSERT INTO eventlog(eventname, username)
                VALUES(event, user);
        ELSIF event = ''SERVERERROR'' THEN
            Err_num := SERVER_ERROR(1);
            INSERT INTO eventlog(eventname, srv_error)
                VALUES(event, err_num);
        ELSE
            Instance := INSTANCE_NUM;
            Dbname := DATABASE_NAME;
            INSERT INTO eventlog(eventname, inst_num, db_name)
                VALUES(event, instance, dbname);
  END IF;
END;

');

-- 创建LOGOFF和SHUTDOWN 事件触发器
DBMS_UTILITY.EXEC_DDL_STATEMENT('
CREATE OR REPLACE TRIGGER trig4_before
BEFORE LOGOFF OR SHUTDOWN
ON DATABASE
DECLARE
Event VARCHAR2(20);
Instance NUMBER;
Dbname VARCHAR2(50);
User VARCHAR2(30);
BEGIN
Event := SYSEVENT;
IF event = ''LOGOFF'' THEN
User := LOGIN_USER;
INSERT INTO eventlog(eventname, username)
VALUES(event, user);
ELSE
Instance := INSTANCE_NUM;
Dbname := DATABASE_NAME;
INSERT INTO eventlog(eventname, inst_num, db_name)
VALUES(event, instance, dbname);
END IF;
END;
');
END;

CREATE TABLE mydata(mydate NUMBER);
CONNECT SCOTT/TIGER

COL eventname FORMAT A10
COL eventdate FORMAT A12
COL username FORMAT A10
COL obj_type FORMAT A15
COL obj_name FORMAT A15
COL obj_owner FORMAT A10
SELECT eventname, eventdate, obj_type, obj_name, obj_owner, username, Srv_error
FROM eventlog;

DROP TRIGGER trig4_ddl;
DROP TRIGGER trig4_before;
DROP TRIGGER trig4_after;
DROP TABLE eventlog;
DROP TABLE mydata;

8.6 数据库触发器的应用实例
用户可以使用数据库触发器实现各种功能:
l 复杂的审计功能;
例:将EMP 表的变化情况记录到AUDIT_TABLE和AUDIT_TABLE_VALUES中。

CREATE TABLE audit_table(
Audit_id NUMBER,
User_name VARCHAR2(20),
Now_time DATE,
Terminal_name VARCHAR2(10),
Table_name VARCHAR2(10),
Action_name VARCHAR2(10),
Emp_id NUMBER(4));

CREATE TABLE audit_table_val(
Audit_id NUMBER,
Column_name VARCHAR2(10),
Old_val NUMBER(7,2),
New_val NUMBER(7,2));

CREATE SEQUENCE audit_seq
START WITH 1000
INCREMENT BY 1
NOMAXVALUE
NOCYCLE NOCACHE;

CREATE OR REPLACE TRIGGER audit_emp
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW
DECLARE
Time_now DATE;
Terminal CHAR(10);
BEGIN
Time_now:=sysdate;
Terminal:=USERENV('TERMINAL');
IF INSERTING THEN
INSERT INTO audit_table
VALUES(audit_seq.NEXTVAL, user, time_now,
terminal, 'EMP', 'INSERT', :new.empno);
ELSIF DELETING THEN
INSERT INTO audit_table
VALUES(audit_seq.NEXTVAL, user, time_now,
terminal, 'EMP', 'DELETE', :old.empno);
ELSE
INSERT INTO audit_table
VALUES(audit_seq.NEXTVAL, user, time_now,
terminal, 'EMP', 'UPDATE', :old.empno);
IF UPDATING('SAL') THEN
INSERT INTO audit_table_val
VALUES(audit_seq.CURRVAL, 'SAL', :old.sal, :new.sal);
ELSE UPDATING('DEPTNO')
INSERT INTO audit_table_val
VALUES(audit_seq.CURRVAL, 'DEPTNO', :old.deptno, :new.deptno);
END IF;
END IF;
END;

l 增强数据的完整性管理;
例:修改DEPT表的DEPTNO列时,同时把EMP表中相应的DEPTNO也作相应的修改;

CREATE SEQUENCE update_sequence
INCREMENT BY 1
START WITH 1000
MAXVALUE 5000 CYCLE;

ALTER TABLE emp
ADD update_id NUMBER;

CREATE OR REPLACE PACKAGE integritypackage AS
Updateseq NUMBER;
END integritypackage;

CREATE OR REPLACE PACKAGE BODY integritypackage AS
END integritypackage;

CREATE OR REPLACE TRIGGER dept_cascade1
BEFORE UPDATE OF deptno ON dept
DECLARE
Dummy NUMBER;
BEGIN
SELECT update_sequence.NEXTVAL INTO dummy FROM dual;
Integritypackage.updateseq:=dummy;
END;

CREATE OR REPLACE TRIGGER dept_cascade2
AFTER DELETE OR UPDATE OF deptno ON dept
FOR EACH ROW
BEGIN
IF UPDATING THEN
UPDATE emp SET deptno=:new.deptno,
update_id=integritypackage.updateseq
WHERE emp.deptno=:old.deptno AND update_id IS NULL;
END IF;
IF DELETING THEN
DELETE FROM emp
WHERE emp.deptno=:old.deptno;
END IF;
END;

CREATE OR REPLACE TRIGGER dept_cascade3
AFTER UPDATE OF deptno ON dept
BEGIN
UPDATE emp SET update_id=NULL
WHERE update_id=integritypackage.updateseq;
END;

SELECT * FROM EMP ORDER BY DEPTNO;
UPDATE dept SET deptno=25 WHERE deptno=20;

l 帮助实现安全控制;
例:保证对EMP表的修改仅在工作日的工作时间;

CREATE TABLE company_holidays(day DATE);

INSERT INTO company_holidays
VALUES(sysdate);
INSERT INTO company_holidays
VALUES(TO_DATE('21-10月-01', 'DD-MON-YY'));

CREATE OR REPLACE TRIGGER emp_permit_change
BEFORE INSERT OR DELETE OR UPDATE ON emp
DECLARE
Dummy NUMBER;
Not_on_weekends EXCEPTION;
Not_on_holidays EXCEPTION;
Not_working_hours EXCEPTION;
BEGIN
/* check for weekends /
IF TO_CHAR(SYSDATE, 'DAY') IN ('星期六', '星期日') THEN
RAISE not_on_weekends;
END IF;
/
check for company holidays /
SELECT COUNT(
) INTO dummy FROM company_holidays
WHERE TRUNC(day)=TRUNC(SYSDATE);
IF dummy >0 THEN
RAISE not_on_holidays;
END IF;
/* check for work hours(8:00 AM to 18:00 PM */
IF (TO_CHAR(SYSDATE,'HH24')18) THEN
RAISE not_working_hours;
END IF;
EXCEPTION
WHEN not_on_weekends THEN
RAISE_APPLICATION_ERROR(-20324,
'May not change employee table during the weekends');
WHEN not_on_holidays THEN
RAISE_APPLICATION_ERROR(-20325,
'May not change employee table during a holiday');
WHEN not_working_hours THEN
RAISE_APPLICATION_ERROR(-20326,
'May not change employee table during no_working hours');
END;

wangtong1234567
sky小糊涂神 不得不说,没有你这样回答问题的,你完全影响了这个提问,大家都会没心情去回答了!
3 年多之前 回复

我擦,直接刷屏啊,楼上

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
ORACLE 触发器疑难问题提
ORACLE 触发器 (某些存储过程向某个表插入数据时,想写一个触实现发器针对每一条数据插入一个唯一序列号) 因为修改这些存储过程不好修改,所以想通过触发器来实现。
oracle触发器问题
oracle的触发器运行时报错,有没有什么好的测试工具,或者调试方法啊?
ORACLE创建触发器的问题
下面是在SQLSERVER中创建的触发器 CREATE TRIGGER [dbo].[TRI_CUP_UPDATE_DEL] ON [dbo].[cup] AFTER UPDATE,DELETE AS BEGIN declare @name1 varchar(1000) declare @name2 varchar(1000) select @name1=MARK from deleted select @name2=MARK from inserted if(@name1=@name2 or (@name2 is null and @name1 is not null)) begin update cup set mark='0' where id in (SELECT id FROM DELETED) end END 比如:当前表cup的某条记录被更新或者删除时(此条记录的id为1,id不是主键,也没有唯一约束),本表id为1 的所有记录的mark字段的值都变为0; 问题: 在oracle中怎么创建一个触发器,实现同样的功能。 谢谢各位大佬!
关于oracle触发器操作的疑问
<div class="iteye-blog-content-contain" style="font-size: 14px;"> <p> 首先说明我要实现的功能:假设A表和B表,我想实现,在增加A表的同时,利用刚刚插入的数据和A表中已有的数据(包括刚刚插入的数据)进行如数据编码(code)组合,生成一个新的字符串插入到B表中的编码列;</p> <p>我使用的Oracle客户端是PL/SQL devloper 8,</p> <p>我现在想到的方案:</p> <p>方案1:使用行触发器,在插入的时候使用new获取刚刚插入的数据,这样跟之前已经有的数据组合,但是这样当插入两条或多条的时候,会出现下一条总是无法和刚刚插入的数据组合,也就是不能发现同一批插入的数据;(按道理,两个SQL语句应该是两个事务,应该能使用刚刚插入的数据,这是第一个疑问,是不是客户端造成的,我的客户端设置是自动提交SQL,不应该有问题)</p> <p>方案2:在第一种方案不能满足需求,我寻求了第二种方案,就是建立一个全局临时表,然后使用行触发器把新插入的数据放到临时表中,再最后做一次语句触发器,在语句级触发器中使用游标遍历临时表记录,跟已经存在的数据进行组合,插入到B表中;(疑问2:在插入多条数据的时候,比如两个insert语句,行触发器在临时表新增一条数据,然后触发了一次语句级触发器,然后行触发器在临时表又新增一条数据,然后又触发了一次语句级触发器,跟我预想的应该是两次行触发器,一次最终语句级触发不一样,不知道是不是我理解的不对;按照我的理解,两个insert语句应该是两个事务,这样临时表只会保留一条记录,但是目前确实是多条;如果两条insert在一个事务内,为什么又多次触发语句级触发器?);目前解决方法就是在语句触发器最后增加一条删除临时表数据,这样保证临时表始终是最新插入的数据。代码如下:</p> <p> </p> <pre name="code" class="sql"> CREATE TABLE A   ( id number, name varchar2(30), birthdate date   ) ;</pre> <p> </p> <pre name="code" class="java">-- B表 CREATE TABLE B   ( id number, name varchar2(30), birthdate date   ) ;</pre> <p> </p> <pre name="code" class="java">-- 创建临时表 a_tt,存储刚刚插入的数据 CREATE global temporary TABLE a_tt   (id number, name varchar2(30), birthdate date   ) ON COMMIT DELETE ROWS;</pre> <pre name="code" class="java"> --A表的行触发器记录新插入的数据 create or replace trigger a_insert_row AFTER insert on A for each row declare begin insert into <span style="font-size: 1em; line-height: 1.5;">a_tt</span><span style="font-size: 1em; line-height: 1.5;">(id,name,birthdate) values(:new.id,:new.name,:new.birthdate);</span> end; </pre> <p> </p> <pre name="code" class="java"> create or replace trigger aaaa_insert_tt AFTER insert on A declare v_name aaaa_log.name%type; cursor n_cur is select name from <span style="font-size: 1em; line-height: 1.5;">a_tt</span><span style="font-size: 1em; line-height: 1.5;">;</span> begin dbms_output.put_line('语句触发器执行'); for cur in n_cur loop dbms_output.put_line( cur.name); insert into B(name) select cur.name ||'_' ||name from A; end loop; -- delete from <span style="font-size: 1em; line-height: 1.5;">a_tt</span><span style="font-size: 1em; line-height: 1.5;">; --删除临时表过时数据 </span> end;</pre> <p> 测试语句:</p> <p> insert  into A  values(2,'a',sysdate);         </p> <p>insert  into A values(3,'b',sysdate);</p> <p> </p> <p>预期结果:B表中name 列 2_2,3_2,3_3</p> <p> </p> <p>希望各位大神,帮我理理思路,不知道我说清没有</p> <p>触发器执行的时候是不是在行触发器(after)之后提交数据,在语句级触发器就可以使用提交后的数据</p> <p> </p> </div>
新人求教ORACLE 触发器的问题
表1为映射表,存在A1和B1两个字段,要求在表2插入数据时,数据中的A2(A2=A1)根据表1变为对应的b1,这个触发器改如何写
oracle触发器的问题
表A 和 表B,表B的外键是表A的主键。两个表存在一对多的关系。 现在: 当更新表A,并且表A的字段 colum1 的值为1的时候,执行以下操作: 1、为表B插入12条数据 2、表B的主键自增。 3、表B的外键是刚插入的表A的主键值。 例如: 表A有三个字段(id,year,status) 表B有三个字段(id,year,month,color) 当执行 update A set year = '2013' and status = '1' where id = '0001' 这条语句的时候触发以下SQL语句 inset into B vaalues(1,2,3,4) 1:id的值实现自增。 2:year 等于刚才的update语句的year字段的值。 3:month = 从1-12这个12个月(就是说要一次增加12条记录,前面id和year不变,month=从1到12) 4:随便写。 请问这样的触发器该怎么写。
用navicat创建oracle触发器中遇到的问题
**求大神指导,在navicat中创建Oracle 触发器** **把JCY_DEMO表中插入或者更新name=''小黄'的数据同步到JCY_TEST表中** ![图片说明](https://img-ask.csdn.net/upload/201905/07/1557198086_952870.png) **调试之后显示** ![图片说明](https://img-ask.csdn.net/upload/201905/07/1557198133_235446.png) **执行insert语句之后显示** ![图片说明](https://img-ask.csdn.net/upload/201905/07/1557198237_584184.png)
oracle触发器的问题,求大神详细解决一下
我建立了表1(ID,NAME,AGE)和表2(COUNNT)。制作了触发器,当表1进行增删改的时候,表2中的COUNNT值+1。 现在的问题是 当表1修改的时候,表2的COUNNT值不变。附触发器代码一张![图片说明](https://img-ask.csdn.net/upload/201704/11/1491897816_17147.png) 之后在百度上查到了序列,有写了一段序列,发现没有用,附序列代码一张!!![图片说明](https://img-ask.csdn.net/upload/201704/11/1491897950_590028.png)
oracle 中建触发器问题
在Oracle中是否可以建立这样一个触发器,当某张表中除了某个字段的值发生改变,那么就将这个字段的值设为1(该字段原来的值为0) 如: create or replace trigger Test after update of res_name on as_res --这里以改变某个字段为例 for each row begin update as_res set is_roredis='1' where res_id=:old.res_id; end Test; 这样报错:触发器不能读它。 不能操作的是同一张表吗?我说的那种需求可以做到吗?
Oracle触发器能否对正在写入的表格进行读写?
###问题背景 本来是想要在删除一个表的某个数据的同时将其余数据的id修正为连续的(因为删除某个数据可能导致id出现间断) </br></br> ###问题所在 触发器是正常地生成了,没有编译错误,但是删除数据的时候却报错了,报错如下图所示: </br></br> ![图片说明](https://img-ask.csdn.net/upload/201911/25/1574686770_801451.png) </br></br> 点进去一看,原来定义游标的时候就已经错了。。。</br></br> ![图片说明](https://img-ask.csdn.net/upload/201911/25/1574686863_528478.png) </br></br> ###问题代码 ```sql create or replace trigger trigger_when_del_guide after delete on test_guide for each row declare v_type varchar2(2);--id转化为字符串所需要拼接的前缀(''、'0'、'00') v_next numeric(3, 0);--下一个id的number值 cursor cur_all_guide_id--游标遍历所有剩余id is select guide_id from test_guide order by guide_id; id_i test_guide.guide_id%type;--游标循环变量id_i begin open cur_all_guide_id; fetch cur_all_guide_id into id_i; while cur_all_guide_id%found loop v_next := cur_all_guide_id%rowcount; case length(v_next) when 1 then v_type := '00'; when 2 then v_type := '0'; else v_type := ''; end case; update test_guide set guide_id=v_type||v_next where guide_id=id_i; end loop; end; ``` ###尝试解决 到网上找了很久,但是基本上就只能得到下面这条信息 * 不能对正在进行写入操作的表进行读写。 ###最终问题 到底有没有什么可行的办法,能够实现我想实现的这个操作?想听听大家的看法(From一个在校学Oracle的菜鸟) 在删除某记录后修改其他全部记录(不重新生成第二张表,除非是能在触发器执行时删除、触发器执行完毕后自动销毁的临时表)
oracle中关于触发器的问题
如何在oracle中定义一个触发器,在SC表插入学生选课信息前检查,如果student中没有相应的学号,现在其中加入该学生学号信息(学生表除学号外,其他属性允许为空) student(sno,sname,ssex,sage,sdept) sc(sno,cno,grade) 我自己定义了一个 create or replace trigger tri_sc before insert on sc for each row begin if :old.sno!=:new.sno then INSERT INTO STUDENT(SNO) VALUES (:new.sno); end if; end; 但是这个在sc表插入数据后,不会在student表插入新数据 烦请各位大佬帮我看看,要怎么设计这个触发器
一个ORACLE触发器的问题
![图片说明](https://img-ask.csdn.net/upload/201710/27/1509092060_507193.png) ![图片说明](https://img-ask.csdn.net/upload/201710/27/1509092070_616588.png) 如上图,第一张是触发器,第二张是PL/SQL更改taxno字段保存,就加了两个空格
写oracle 触发器 一张表的某个字段更新为0 或1 则把这张表数据插入到另一张表
写oracle 触发器 一张表的某个字段更新为0 或1 则把这张表数据插入到另一张表, 刚接触oracle,不懂,请赐教,谢谢!
Oracle触发器不能读取表的问题
12、假设有这样一张用户表表结构如下:UserInfo(id ,username,userPass),希望向表中增加数据时,表中id列的数字自动生成。(选做) 1)第一步创建序列,要求开始的数字为1,每次递增1,按顺序产生序列值; 2)第二步创建一个触发器,向用户表中插入数据的时候触发触发器,在触发器内部调用序列并生成一个序列值赋值给表的id列。 触发器: ``` create or replace trigger pro_id after insert on userinfo for each row begin update userinfo set id=seq_id.nextval where username=:new.username; end; ``` 执行该语句时出错: ``` insert into userinfo(username, userpass) values('李四',123456); ``` 在行 1 上开始执行命令时出错: insert into userinfo(username, userpass) values('李四',123456) 错误报告: SQL 错误: ORA-04091: 表 SCOTT.USERINFO 发生了变化, 触发器/函数不能读它 ORA-06512: 在 "SCOTT.PRO_ID", line 2 ORA-04088: 触发器 'SCOTT.PRO_ID' 执行过程中出错 04091. 00000 - "table %s.%s is mutating, trigger/function may not see it" *Cause: A trigger (or a user defined plsql function that is referenced in this statement) attempted to look at (or modify) a table that was in the middle of being modified by the statement which fired it. *Action: Rewrite the trigger (or function) so it does not read that table. 请问哪里出错了?
请教一个oracle 触发器的问题
我想写这样一个触发器:表A中一行数据只要发生变化(增、删、改),就将这条数据更新到表B(同时将操作数据的时间也记录在表B中的时间字段),并在B中的标记字段中表明是发生了什么操作。谢谢各位达人了……
Oracle触发器,求大神详细讲解
有一个想法, 首先创建一个表,有ID(主键),NAME,AGE 再创建一个表,表内有count。 制作一个触发器,如果用户对第一个表进行增删改的时候,触发触发器,对第二个表的count进行+1。 求解决,小白懂得少,希望大神教学,谢谢
oracle触发器定时执行
请高手帮忙写一个触发器,当表中插入数据时,一段时间后(3分钟或者5分钟)自动 修改表中最新数据(有插入时间字段)的某个字段为false或者为1;
oracle触发器导致ORA-03113错误
场景:使用dblink加触发器同步两个库的数据,源数据库使用11g(11.2.0.1.0),目标数据库使用11g(11.2.0.1.0)。向源数据库中插入记录时,数据无法同步至目标库。并抛出ORA-03113异常。当源数据库使用12c时,一切正常,数据可能同步。 ``` -- 创建dblink CREATE PUBLIC DATABASE LINK datasync CONNECT TO kxmadmin IDENTIFIED BY "123456" USING '(DESCRIPTION =(ADDRESS_LIST =(ADDRESS =(PROTOCOL = TCP)(HOST = 192.168.100.92)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = kxm)))'; -- 创建同义词 create public synonym T_STATISTICS_ATTR_WEEK_HK for T_STATISTICS_ATTR_WEEK @DATASYNC; -- 创建触发器 CREATE OR REPLACE TRIGGER TEMP_trigger BEFORE INSERT ON T_STATISTICS_ATTR_WEEK FOR EACH ROW BEGIN IF INSERTING THEN INSERT INTO T_STATISTICS_ATTR_WEEK_HK ( ATTR, TIMEFLAG, COUNT, CREATETIME ) VALUES ( : NEW .ATTR, : NEW .TIMEFLAG, : NEW . COUNT, : NEW .CREATETIME ) ; END IF; END ; ``` ![图片说明](https://img-ask.csdn.net/upload/201908/16/1565937474_797263.png) oracle日志如下: ``` Trace file e:\app\administrator\diag\rdbms\kxm\kxm\trace\kxm_ora_6856.trc Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options Windows NT Version V6.2 CPU : 12 - type 8664, 6 Physical Cores Process Affinity : 0x0x0000000000000000 Memory (Avail/Total): Ph:7791M/16213M, Ph+PgF:20654M/32597M Instance name: kxm Redo thread mounted by this instance: 1 Oracle process number: 41 Windows thread id: 6856, image: ORACLE.EXE (SHAD) *** 2019-08-16 14:36:23.310 *** SESSION ID:(110.677) 2019-08-16 14:36:23.310 *** CLIENT ID:() 2019-08-16 14:36:23.310 *** SERVICE NAME:(kxm) 2019-08-16 14:36:23.310 *** MODULE NAME:(navicat.exe) 2019-08-16 14:36:23.310 *** ACTION NAME:() 2019-08-16 14:36:23.310 --------Dumping Sorted Master Trigger List -------- Trigger Owner : KXMADMIN Trigger Name : HDS_TEMP_TRIGGER --------Dumping Trigger Sublists -------- trigger sublist 0 : trigger sublist 1 : trigger sublist 2 : trigger sublist 3 : Trigger Owner : KXMADMIN Trigger Name : HDS_TEMP_TRIGGER trigger sublist 4 : Exception [type: ACCESS_VIOLATION, UNABLE_TO_READ] [ADDR:0xA] [PC:0xAD7DF32, pevm_BIND()+258] Incident 20729 created, dump file: e:\app\administrator\diag\rdbms\kxm\kxm\incident\incdir_20729\kxm_ora_6856_i20729.trc ORA-07445: exception encountered: core dump [pevm_BIND()+258] [ACCESS_VIOLATION] [ADDR:0xA] [PC:0xAD7DF32] [UNABLE_TO_READ] [] ```
相见恨晚的超实用网站
相见恨晚的超实用网站 持续更新中。。。
Java学习的正确打开方式
在博主认为,对于入门级学习java的最佳学习方法莫过于视频+博客+书籍+总结,前三者博主将淋漓尽致地挥毫于这篇博客文章中,至于总结在于个人,实际上越到后面你会发现学习的最好方式就是阅读参考官方文档其次就是国内的书籍,博客次之,这又是一个层次了,这里暂时不提后面再谈。博主将为各位入门java保驾护航,各位只管冲鸭!!!上天是公平的,只要不辜负时间,时间自然不会辜负你。 何谓学习?博主所理解的学习,它是一个过程,是一个不断累积、不断沉淀、不断总结、善于传达自己的个人见解以及乐于分享的过程。
程序员必须掌握的核心算法有哪些?
由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法。这些算法与数据结构的学习大多数是零散的,并没有一本把他们全部覆盖的书籍。下面是我觉得值得学习的一些算法以及数据结构,当然,我也会整理一些看过...
有哪些让程序员受益终生的建议
从业五年多,辗转两个大厂,出过书,创过业,从技术小白成长为基层管理,联合几个业内大牛回答下这个问题,希望能帮到大家,记得帮我点赞哦。 敲黑板!!!读了这篇文章,你将知道如何才能进大厂,如何实现财务自由,如何在工作中游刃有余,这篇文章很长,但绝对是精品,记得帮我点赞哦!!!! 一腔肺腑之言,能看进去多少,就看你自己了!!! 目录: 在校生篇: 为什么要尽量进大厂? 如何选择语言及方...
大学四年自学走来,这些私藏的实用工具/学习网站我贡献出来了
大学四年,看课本是不可能一直看课本的了,对于学习,特别是自学,善于搜索网上的一些资源来辅助,还是非常有必要的,下面我就把这几年私藏的各种资源,网站贡献出来给你们。主要有:电子书搜索、实用工具、在线视频学习网站、非视频学习网站、软件下载、面试/求职必备网站。 注意:文中提到的所有资源,文末我都给你整理好了,你们只管拿去,如果觉得不错,转发、分享就是最大的支持了。 一、电子书搜索 对于大部分程序员...
linux系列之常用运维命令整理笔录
本博客记录工作中需要的linux运维命令,大学时候开始接触linux,会一些基本操作,可是都没有整理起来,加上是做开发,不做运维,有些命令忘记了,所以现在整理成博客,当然vi,文件操作等就不介绍了,慢慢积累一些其它拓展的命令,博客不定时更新 free -m 其中:m表示兆,也可以用g,注意都要小写 Men:表示物理内存统计 total:表示物理内存总数(total=used+free) use...
比特币原理详解
一、什么是比特币 比特币是一种电子货币,是一种基于密码学的货币,在2008年11月1日由中本聪发表比特币白皮书,文中提出了一种去中心化的电子记账系统,我们平时的电子现金是银行来记账,因为银行的背后是国家信用。去中心化电子记账系统是参与者共同记账。比特币可以防止主权危机、信用风险。其好处不多做赘述,这一层面介绍的文章很多,本文主要从更深层的技术原理角度进行介绍。 二、问题引入 假设现有4个人...
程序员接私活怎样防止做完了不给钱?
首先跟大家说明一点,我们做 IT 类的外包开发,是非标品开发,所以很有可能在开发过程中会有这样那样的需求修改,而这种需求修改很容易造成扯皮,进而影响到费用支付,甚至出现做完了项目收不到钱的情况。 那么,怎么保证自己的薪酬安全呢? 我们在开工前,一定要做好一些证据方面的准备(也就是“讨薪”的理论依据),这其中最重要的就是需求文档和验收标准。一定要让需求方提供这两个文档资料作为开发的基础。之后开发...
网页实现一个简单的音乐播放器(大佬别看。(⊙﹏⊙))
今天闲着无事,就想写点东西。然后听了下歌,就打算写个播放器。 于是乎用h5 audio的加上js简单的播放器完工了。 演示地点演示 html代码如下` music 这个年纪 七月的风 音乐 ` 然后就是css`*{ margin: 0; padding: 0; text-decoration: none; list-...
Python十大装B语法
Python 是一种代表简单思想的语言,其语法相对简单,很容易上手。不过,如果就此小视 Python 语法的精妙和深邃,那就大错特错了。本文精心筛选了最能展现 Python 语法之精妙的十个知识点,并附上详细的实例代码。如能在实战中融会贯通、灵活使用,必将使代码更为精炼、高效,同时也会极大提升代码B格,使之看上去更老练,读起来更优雅。
数据库优化 - SQL优化
以实际SQL入手,带你一步一步走上SQL优化之路!
2019年11月中国大陆编程语言排行榜
2019年11月2日,我统计了某招聘网站,获得有效程序员招聘数据9万条。针对招聘信息,提取编程语言关键字,并统计如下: 编程语言比例 rank pl_ percentage 1 java 33.62% 2 cpp 16.42% 3 c_sharp 12.82% 4 javascript 12.31% 5 python 7.93% 6 go 7.25% 7 p...
通俗易懂地给女朋友讲:线程池的内部原理
餐盘在灯光的照耀下格外晶莹洁白,女朋友拿起红酒杯轻轻地抿了一小口,对我说:“经常听你说线程池,到底线程池到底是个什么原理?”
《奇巧淫技》系列-python!!每天早上八点自动发送天气预报邮件到QQ邮箱
将代码部署服务器,每日早上定时获取到天气数据,并发送到邮箱。 也可以说是一个小型人工智障。 知识可以运用在不同地方,不一定非是天气预报。
经典算法(5)杨辉三角
杨辉三角 是经典算法,这篇博客对它的算法思想进行了讲解,并有完整的代码实现。
英特尔不为人知的 B 面
从 PC 时代至今,众人只知在 CPU、GPU、XPU、制程、工艺等战场中,英特尔在与同行硬件芯片制造商们的竞争中杀出重围,且在不断的成长进化中,成为全球知名的半导体公司。殊不知,在「刚硬」的背后,英特尔「柔性」的软件早已经做到了全方位的支持与支撑,并持续发挥独特的生态价值,推动产业合作共赢。 而对于这一不知人知的 B 面,很多人将其称之为英特尔隐形的翅膀,虽低调,但是影响力却不容小觑。 那么,在...
腾讯算法面试题:64匹马8个跑道需要多少轮才能选出最快的四匹?
昨天,有网友私信我,说去阿里面试,彻底的被打击到了。问了为什么网上大量使用ThreadLocal的源码都会加上private static?他被难住了,因为他从来都没有考虑过这个问题。无独有偶,今天笔者又发现有网友吐槽了一道腾讯的面试题,我们一起来看看。 腾讯算法面试题:64匹马8个跑道需要多少轮才能选出最快的四匹? 在互联网职场论坛,一名程序员发帖求助到。二面腾讯,其中一个算法题:64匹...
面试官:你连RESTful都不知道我怎么敢要你?
干货,2019 RESTful最贱实践
刷了几千道算法题,这些我私藏的刷题网站都在这里了!
遥想当年,机缘巧合入了 ACM 的坑,周边巨擘林立,从此过上了"天天被虐似死狗"的生活… 然而我是谁,我可是死狗中的战斗鸡,智力不够那刷题来凑,开始了夜以继日哼哧哼哧刷题的日子,从此"读题与提交齐飞, AC 与 WA 一色 ",我惊喜的发现被题虐既刺激又有快感,那一刻我泪流满面。这么好的事儿作为一个正直的人绝不能自己独享,经过激烈的颅内斗争,我决定把我私藏的十几个 T 的,阿不,十几个刷题网...
SQL-小白最佳入门sql查询一
不要偷偷的查询我的个人资料,即使你再喜欢我,也不要这样,真的不好;
JavaScript 为什么能活到现在?
作者 | 司徒正美 责编 |郭芮 出品 | CSDN(ID:CSDNnews) JavaScript能发展到现在的程度已经经历不少的坎坷,早产带来的某些缺陷是永久性的,因此浏览器才有禁用JavaScript的选项。甚至在jQuery时代有人问出这样的问题,jQuery与JavaScript哪个快?在Babel.js出来之前,发明一门全新的语言代码代替JavaScript...
项目中的if else太多了,该怎么重构?
介绍 最近跟着公司的大佬开发了一款IM系统,类似QQ和微信哈,就是聊天软件。我们有一部分业务逻辑是这样的 if (msgType = "文本") { // dosomething } else if(msgType = "图片") { // doshomething } else if(msgType = "视频") { // doshomething } else { // doshom...
致 Python 初学者
欢迎来到“Python进阶”专栏!来到这里的每一位同学,应该大致上学习了很多 Python 的基础知识,正在努力成长的过程中。在此期间,一定遇到了很多的困惑,对未来的学习方向感到迷茫。我非常理解你们所面临的处境。我从2007年开始接触 python 这门编程语言,从2009年开始单一使用 python 应对所有的开发工作,直至今天。回顾自己的学习过程,也曾经遇到过无数的困难,也曾经迷茫过、困惑过。开办这个专栏,正是为了帮助像我当年一样困惑的 Python 初学者走出困境、快速成长。希望我的经验能真正帮到你
Python 编程开发 实用经验和技巧
Python是一门很灵活的语言,也有很多实用的方法,有时候实现一个功能可以用多种方法实现,我这里总结了一些常用的方法和技巧,包括小数保留指定位小数、判断变量的数据类型、类方法@classmethod、制表符中文对齐、遍历字典、datetime.timedelta的使用等,会持续更新......
吐血推荐珍藏的Visual Studio Code插件
作为一名Java工程师,由于工作需要,最近一个月一直在写NodeJS,这种经历可以说是一部辛酸史了。好在有神器Visual Studio Code陪伴,让我的这段经历没有更加困难。眼看这段经历要告一段落了,今天就来给大家分享一下我常用的一些VSC的插件。 VSC的插件安装方法很简单,只需要点击左侧最下方的插件栏选项,然后就可以搜索你想要的插件了。 下面我们进入正题 Material Theme ...
实战:如何通过python requests库写一个抓取小网站图片的小爬虫
有点爱好的你,偶尔应该会看点图片文字,最近小网站经常崩溃消失,不如想一个办法本地化吧,把小照片珍藏起来! 首先,准备一个珍藏的小网站,然后就可以开始啦! 第一步 我们先写一个获取网站的url的链接,因为url常常是由page或者,其他元素构成,我们就把他分离出来,我找到的网站主页下有图片区 图片区内有标题页,一个标题里有10张照片大概 所以步骤是: 第一步:进入图片区的标题页 def getH...
“狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作
一、垃圾文字生成器介绍 最近在浏览GitHub的时候,发现了这样一个骨骼清奇的雷人项目,而且热度还特别高。 项目中文名:狗屁不通文章生成器 项目英文名:BullshitGenerator 根据作者的介绍,他是偶尔需要一些中文文字用于GUI开发时测试文本渲染,因此开发了这个废话生成器。但由于生成的废话实在是太过富于哲理,所以最近已经被小伙伴们给玩坏了。 他的文风可能是这样的: 你发现,...
程序员:我终于知道post和get的区别
是一个老生常谈的话题,然而随着不断的学习,对于以前的认识有很多误区,所以还是需要不断地总结的,学而时习之,不亦说乎
《程序人生》系列-这个程序员只用了20行代码就拿了冠军
你知道的越多,你不知道的越多 点赞再看,养成习惯GitHub上已经开源https://github.com/JavaFamily,有一线大厂面试点脑图,欢迎Star和完善 前言 这一期不算《吊打面试官》系列的,所有没前言我直接开始。 絮叨 本来应该是没有这期的,看过我上期的小伙伴应该是知道的嘛,双十一比较忙嘛,要值班又要去帮忙拍摄年会的视频素材,还得搞个程序员一天的Vlog,还要写BU...
加快推动区块链技术和产业创新发展,2019可信区块链峰会在京召开
11月8日,由中国信息通信研究院、中国通信标准化协会、中国互联网协会、可信区块链推进计划联合主办,科技行者协办的2019可信区块链峰会将在北京悠唐皇冠假日酒店开幕。   区块链技术被认为是继蒸汽机、电力、互联网之后,下一代颠覆性的核心技术。如果说蒸汽机释放了人类的生产力,电力解决了人类基本的生活需求,互联网彻底改变了信息传递的方式,区块链作为构造信任的技术有重要的价值。   1...
Python 植物大战僵尸代码实现(2):植物卡片选择和种植
这篇文章要介绍的是: - 上方植物卡片栏的实现。 - 点击植物卡片,鼠标切换为植物图片。 - 鼠标移动时,判断当前在哪个方格中,并显示半透明的植物作为提示。
相关热词 c# 引用mysql c#动态加载非托管dll c# 两个表数据同步 c# 返回浮点json c# imap 链接状态 c# 漂亮字 c# 上取整 除法 c#substring c#中延时关闭 c#线段拖拉
立即提问