避免在触发器中重写相同的代码

时间:2013-12-05 11:46:38

标签: sql oracle triggers

我正在使用表格在数据库级别编写数据验证。

以下是我用于验证的表格结构:(理解记录有限)

 SRNO | COL_NAME | OBJ_NAME | IS_MANDATORY | ALTER_COL | ERROR_MSG
 1    | TITLE    | Customer | Y            |           | Enter first name!
 2    | FNAME    | Customer | Y            | LNAME     | Either first or last name are required!
 3    | MNAME    | Customer | N            |           | 
 4    | LNAME    | Customer | Y            | FNAME     | Either first or last name are required!

我已经编写了触发器,在根据validation表将数据插入数据库之前对其进行验证:

CREATE OR REPLACE TRIGGER VALIDATE_CUST 
    BEFORE INSERT ON CUSTOMER REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW
DECLARE
    T_COL_VAL NUMBER(4);
BEGIN
    IF INSERTING THEN
        FOR C IN
            (select COL_NAME,ERROR_MSG from VALIDATE_COLS where IS_MANDATORY='Y' and OBJ_NAME='Customer' order by SRNO)
        LOOP
        T_COL_VAL := CASE C.COL_NAME
                WHEN 'TITLE' THEN nvl(length(:NEW.TITLE),0)
                WHEN 'FNAME' THEN nvl(length(:NEW.FNAME),0)
                WHEN 'MNAME' THEN nvl(length(:NEW.MNAME),0)
                WHEN 'LNAME' THEN nvl(length(:NEW.LNAME),0)
            ELSE length('OK')
        END;
        IF T_COL_VAL=0 THEN
            RAISE_APPLICATION_ERROR(-20001,C.ERROR_MSG);
        END IF;
        END LOOP;
    END IF;
END;

以上触发器检查所有强制字段是否具有值。以上触发工作正常。

现在我想使用ALTER_COL表中的validations列。如果原始列为null,将检查ALTER_COL列。例如,FNAMELNAME都是强制性的。因此,如果未提供FNAME,则触发器必须在引发错误之前检查LNAME,并且仅当LNAME也为空时才会引发错误。

我的问题是,我需要在if条件下重写case语句以获得ALTER_COL的长度,如:

IF T_COL_VAL=0 THEN
    --if `ALTER_COL` is not null
    --Write case statement again to get the length of `ALTER_COL`
    --If length of `ALTER_COL` is 0 then only raise following error
    RAISE_APPLICATION_ERROR(-20001,C.ERROR_MSG);
END IF;

或者有更好的方法吗?

任何建议都将不胜感激!

Update1 (在@Wernfried回答之后)

我尝试编写可以避免重写代码的函数,但是我无法将NEW传递给函数。我试过的功能看起来像。

CREATE FUNCTION FN_VALIDATE_CUST(COL_NAME in VARCHAR) return NUMBER as
BEGIN
 return CASE COL_NAME
        WHEN 'FNAME' THEN nvl(length(:NEW.FNAME),0)
        WHEN 'MNAME' THEN nvl(length(:NEW.MNAME),0)
        WHEN 'LNAME' THEN nvl(length(:NEW.LNAME),0)
        WHEN 'TITLE' THEN nvl(length(:NEW.TITLE),0)
        ELSE length('OK')
    END;
END;

我无法将NEW对象传递给上面的函数来访问列值。因此,如果我使用函数,我将需要在触发事件中编写case语句。

2 个答案:

答案 0 :(得分:3)

  
    

或者有更好的方法吗?

  

当然 - 在数据库中使用NOT NULL和CHECK约束来执行此操作。这就是他们的目标,他们比你的方法更高效,更可靠,更灵活。

如果确实需要为违反约束提供自定义错误消息,请确保命名约束,并提供违反约束时要使用的自定义消息表。

编辑...

如果约束的强制取决于另一个表中是否存在客户编号,那么我宁愿在表中有一个标志,指示是否应用检查而不是空约束,并将其包含在约束定义。

例如:

... add constraint lname_required check (apply_constraints = 0 or lname is not null)

我不认为在这种情况下你可以避免需要触发器,因为你必须根据另一个表中客户编号的存在将“apply_constraints”的值保持为1(确保该表上的删除或插入更新此表中的相关值。

答案 1 :(得分:1)

您可以编写程序并在触发器中调用此过程。