简体   繁体   English

Oracle SQL触发更新问题-研究/学习

[英]Oracle SQL trigger on update issue - Study / learnings

I have created a copy of an existing database (I_Customer) with the below code: 我已使用以下代码创建了现有数据库(I_Customer)的副本:

CREATE TABLE N_CUSTOMER AS SELECT * FROM I_CUSTOMER;

I have created the below table that will act as a log for modifications to the N_Customer table: 我创建了下表,该表将用作修改N_Customer表的日志:

CREATE TABLE CUSTOMER_CHANGELOG 
( cust_no NUMBER(5),
cust_name VARCHAR2(20),
contact VARCHAR2(20),
log_date DATE);

I have also created (with help from a stack member) the below trigger that will fire after the N_Customer table is edited and write some specific fields (new and old) tot he Customer_Changelog table: 我还创建了(在堆栈成员的帮助下)以下触发器,该触发器将在编辑N_Customer表并向Customer_Changelog表中写入一些特定字段(新的和旧的)后触发:

CREATE OR REPLACE 
TRIGGER customer_up_tr
AFTER UPDATE ON n_customer
FOR EACH ROW
WHEN (OLD.contact <> 1 AND NEW.contact = 1 OR OLD.cust_name <> 1 AND NEW.cust_name = 1)
BEGIN
      INSERT INTO customer_changelog (cust_no, cust_name, contact, log_date) VALUES (:OLD.cust_no, :OLD.cust_name, :OLD.contact, sysdate);
      INSERT INTO customer_changelog (cust_no, cust_name, contact, log_date) VALUES (:NEW.cust_no, :NEW.cust_name, :NEW.contact, sysdate);
END;

Now when I use the below code to edit the N_Customer table: 现在,当我使用以下代码编辑N_Customer表时:

UPDATE N_CUSTOMER
SET cust_name = 'Peter Davis', contact = 'Sam Bogdanovich'
WHERE cust_no = 2338;

I get this error: 我收到此错误:

UPDATE N_CUSTOMER
*
ERROR at line 1: 
ORA-01722: invalid number 

Now my data types etc all match so I am not sure what could be causing this. 现在我的数据类型等都匹配了,所以我不确定是什么原因造成的。

Any ideas would be much appreciated. 任何想法将不胜感激。

The problem is in this line of the trigger: 问题出在触发器的这一行:

(OLD.contact <> 1 AND NEW.contact = 1 OR OLD.cust_name <> 1 AND NEW.cust_name = 1)

Contact and cust_name fields are VARCHAR2, but the trigger is comparing them to a number. Contact和cust_name字段是VARCHAR2,但是触发器正在将它们与数字进行比较。

This simple example will fail with the same error: 这个简单的示例将因相同的错误而失败:

SELECT 1 FROM DUAL
WHERE 'abc' <> 1;

The expression OLD.contact <> 1 is comparing the character column contact to a number (This is also known as "comparing apples to oranges"). 表达式OLD.contact <> 1字符列的contact与一个数字进行比较(这也称为“将苹果与橙子进行比较”)。

Because the conversion of a number to a character is ambigous (it could be converted to '01', '001' ...) Oracle will do it the other way round and convert the character value to a number (because that is non-amgigous '01' , '001' will both result in the number 1`). 由于将数字转换为字符非常困难(可以将其转换为'01', '001' ...) Oracle will do it the other way round and convert the character value to a number (because that is non-amgigous '01' , '001' will both result in the number 1`)。

You apparently have non-numeric values in the contact column (which is to be expected based on the column's name and it's data type) the conversion fails. 显然, contact列中有非数字值(根据列名及其数据类型,这是预期值),转换将失败。

The simple rule is: 简单的规则是:

Never rely on implicit type casting 永远不要依赖隐式类型转换

Use character literals for characters and number literals for numbers. 使用字符文字表示数字,使用数字文字表示数字。 1 is a number. 1是数字。 '1' is a character literal. '1'是字符文字。

Having said all that, you need to change this line: 说了这么多,您需要更改此行:

OLD.contact <> 1 AND NEW.contact = 1 OR OLD.cust_name <> 1 AND NEW.cust_name = 1

to

OLD.contact <> '1' AND NEW.contact = '1' OR OLD.cust_name <> '1' AND NEW.cust_name = '1'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM