尝试限制字符长度时ORA-04098触发错误

时间:2015-01-04 14:53:37

标签: database oracle plsql triggers

我正在尝试为我的数据库表创建一个触发器,以便用户只能输入长度为6到8个字符的邮政编码。但是,即使触发器没有显示任何错误,这似乎也不起作用。

以下是代码:

create or replace trigger loc_postcode
before insert or update of postcode
on location
for each row
begin
    if ( LENGTH(:new.postcode) > 8) or ( LENGTH(:new.postcode) < 6)
         then    raise_application_error(0001,
             'The postcode must be between 6 and 8 characters long');
         end if;
end;​

和错误:

  

ORA-04098:触发'C3392387.LOC_ID'无效且重新验证失败

3 个答案:

答案 0 :(得分:2)

正如其他人所提到的,你的触发器的先前版本的问题在于,当你需要将字符串的长度与值进行比较时,你正在将字符串与数字进行比较。我不会进一步详细说明。

您当前错误的原因是您没有使用有效的错误代码来解决用户定义的错误。每the documentation RAISE_APPLICATION_ERROR个过程会-20000-20999范围内的错误代码。将错误代码更改为-20001the trigger will work

我有点惊讶你得到的错误就是你。我希望你能得到"ORA-21000: error number argument to raise_application_error of 1 is out of range",因为可以证明in this SQL Fiddle。这可能是因为你在最后的分号后有一个略显狡猾的角色。当我在文本编辑器中查看它时,它以十六进制显示一个空格,但是当我将它复制到SQL Fiddle中时它可能不会显示它是如何出现的。它也可能是Stack Exchange渲染引擎的人工制品。

顺便说一下,0001 是有效的Oracle错误代码; 00001是一种唯一的约束违规,会被声明为-00001(请注意减号)。

但是,这不是我要这样做的方式。触发器在使用时会产生额外的开销,并且会混淆可以在数据库中声明的约束。总是存在级联触发器的危险,这可能会使您的数据模型非常复杂。

更简单的方法是将POSTCODE列声明为最多8个字符/字节(由您决定)并在列上添加check constraint以确保长度邮政编码是6个字符(或字节)或更大。这将您需要的逻辑嵌入到表的结构中(从而在Oracle的元数据中),使得查看正在发生的事情变得更加容易。

如果您要将表DDL声明为如下所示(显然大大简化):

create table location ( 
     id number
   , postcode varchar2(8)
   , constraint pk_location primary key (id)
   , constraint ck_location_postcode check (length(postcode) between 6 and 8)
     )

然后你可以获得相同的结果(working SQL Fiddle)。请注意,列POSTCODE的最大长度为8,它处理上限,并且还有一个限制它的检查约束。我已经定义了检查约束来处理上限和下限,以便您可以在将来告诉您打算将8作为上限。因此,更改列的大小不会破坏您的约束。这是一个安全功能,仅此而且可以在不更改功能的情况下声明如下:

   , constraint ck_location_postcode check (length(postcode) >= 6)

答案 1 :(得分:0)

据推测,您希望长度不是值:

create or replace trigger loc_id 
before insert or update of postcode
on location
for each row
begin
         if (length(:new.postcode) > 8) or (length(:new.postcode) < 6)
         then    raise_application_error(
             'The postcode must be between 6 and 8 characters long');
         end if;
end;

您的代码不会生成错误,因为Oracle允许您尝试比较字符串和数字。失败的是字符串不是数字格式。

答案 2 :(得分:0)

看起来POSTCODE是一个字符串。由于您要检查其长度,因此需要使用LENGTH函数。

if ( LENGTH(:new.postcode) > 8) or ( LENGTH(:new.postcode) < 6)

或我个人更喜欢:

if NOT LENGTH(:new.postcode) BETWEEN 6 AND 8 THEN

在您的版本中,您试图将POSTCODE的实际值与数字6和8进行比较,这会导致字符串值无法转换为数字时出错。