2015-01-04 34 views
0

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

下面是代码:

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: trigger 'C3392387.LOC_ID' is invalid and failed re-validation

+2

你触发了名字'loc_postcode'但你的错误消息提到了一个名为'LO​​C_ID'触发 - 有一个错误与也触发? – 2015-01-04 16:00:54

回答

2

正如其他人所说的那样,以前版本的触发器的问题在于,当您需要将字符串的长度与值进行比较时,您将字符串与数字进行比较。我不会就此进一步细节。

当前错误的原因是您没有对用户定义的错误使用有效的错误代码。每the documentationRAISE_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。这可能是因为你在最后一个分号后有一个稍微狡猾的角色。当我在文本编辑器中查看它时,它显示一个Hex格式的空间,但是当我将它复制到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) 
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允许你尝试比较字符串和数字。失败是当字符串不是数字格式时。

+0

嘿,谢谢你的回复,我改变了你的想法,它摆脱了其中一个错误,但另一个仍然存在。 – BiscuitCookie 2015-01-04 15:33:49

+0

“邮编”是一个字符还是数字? – tvCa 2015-01-04 17:26:49

0

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

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

或个人而言,我宁愿:

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

在你的版本中,您要邮编的实际值进行比较,以数字6和8,这将导致一个错误时,字符串值不能转换为数字。

+0

嘿谢谢你的回复,我改变了你的说法,它摆脱了其中一个错误,但另一个仍然存在。 – BiscuitCookie 2015-01-04 15:33:12