【问题标题】:Oracle SQL trigger on update issue - Study / learnings更新问题上的 Oracle SQL 触发器 - 学习/学习
【发布时间】:2013-10-15 22:39:30
【问题描述】:

我已使用以下代码创建了现有数据库 (I_Customer) 的副本:

CREATE TABLE N_CUSTOMER AS SELECT * FROM I_CUSTOMER;

我创建了下表,它将作为修改 N_Customer 表的日志:

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

我还创建了(在堆栈成员的帮助下)以下触发器,该触发器将在编辑 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;

现在当我使用以下代码编辑 N_Customer 表时:

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

我收到此错误:

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

现在我的数据类型等都匹配,所以我不确定是什么原因造成的。

任何想法都将不胜感激。

【问题讨论】:

  • cust_name 和 contact(在 WHEN 子句中使用)是数字吗?
  • 嗨罗恩。不,它们是 VARCHAR2(20)

标签: mysql sql oracle plsql triggers


【解决方案1】:

问题出在触发器的这一行:

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

Contact 和 cust_name 字段是 VARCHAR2,但触发器会将它们与数字进行比较。

这个简单的例子会失败并出现同样的错误:

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

【讨论】:

  • 嗨,肖恩。那么我真的用 abc 替换 1 吗?
  • 没关系。我得到了它。如果我只是删除 WHEN {(OLD.contact 1 AND NEW.contact = 1 OR OLD.cust_name 1 AND NEW.cust_name = 1)} 触发器会满足我的需要。
【解决方案2】:

表达式OLD.contact &lt;&gt; 1 将字符列contact 与一个数字进行比较(这也称为“比较苹果和橙子”)。

因为数字到字符的转换是不明确的(可以转换为'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 number1`)。

您显然在 contact 列中有非数字值(这是根据列的名称和数据类型预期的)转换失败。

简单的规则是:

永远不要依赖隐式类型转换

对字符使用字符文字,对数字使用数字文字。 1 是一个数字。 '1' 是一个字符文字。

说了这么多,你需要改变这一行:

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

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

【讨论】:

    猜你喜欢
    • 2013-10-14
    • 2013-09-30
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 2016-06-09
    • 1970-01-01
    相关资源
    最近更新 更多