ORA-04098 尝试限制字符长度时触发错误
ORA-04098 trigger error when trying to restrict character length
我正在尝试为我的数据库创建一个触发器 table 以便用户只能输入 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: trigger 'C3392387.LOC_ID' is invalid and failed re-validation
据推测,您想要长度而不是值:
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 允许您尝试比较字符串和数字。失败是当字符串不是数字格式时。
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 进行比较,当字符串值无法转换为数字时会导致错误。
正如其他人所提到的,您的触发器的先前版本的问题在于,当您需要将字符串的长度与值进行比较时,您正在将字符串与数字进行比较。我不会对此进行任何进一步的详细说明。
当前错误的原因是您没有为用户定义的错误使用有效的错误代码。每 the documentation the RAISE_APPLICATION_ERROR
procedure takes error codes in the range -20000
to -20999
. Change the error code to -20001
and the trigger will work.
令您感到有些惊讶的是,您遇到了这样的错误。我原以为你会得到 "ORA-21000: error number argument to raise_application_error of 1 is out of range"
,正如可以证明的那样 in this SQL Fiddle。这可能是因为你在最后一个分号后有点狡猾。当我在文本编辑器中查看它时,它以十六进制显示 space,但是当我将它复制到 SQL Fiddle 时判断它的显示方式可能不是。它也可能是 Stack Exchange 渲染引擎的产物。
顺便说一句,0001
不是 有效的 Oracle 错误代码; 00001
是唯一约束违规,将被声明为 -00001
(注意减号)。
但是,我不会这样做。触发器在使用时会产生额外的开销,并且会混淆可以在数据库中声明的约束。级联触发器也总是存在危险,这会使您的数据模型极其复杂。
更简单的方法是声明您的 POSTCODE
列最多为 8 characters/bytes(由您决定)并在该列上添加一个 check constraint确保邮政编码的长度为 6 个字符(或字节)或更长。这将您需要的逻辑嵌入到 table 的结构中(因此嵌入到 Oracle 的元数据中),使查看正在发生的事情变得容易得多。
如果您要将 table 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)
我正在尝试为我的数据库创建一个触发器 table 以便用户只能输入 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: trigger 'C3392387.LOC_ID' is invalid and failed re-validation
据推测,您想要长度而不是值:
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 允许您尝试比较字符串和数字。失败是当字符串不是数字格式时。
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 进行比较,当字符串值无法转换为数字时会导致错误。
正如其他人所提到的,您的触发器的先前版本的问题在于,当您需要将字符串的长度与值进行比较时,您正在将字符串与数字进行比较。我不会对此进行任何进一步的详细说明。
当前错误的原因是您没有为用户定义的错误使用有效的错误代码。每 the documentation the RAISE_APPLICATION_ERROR
procedure takes error codes in the range -20000
to -20999
. Change the error code to -20001
and the trigger will work.
令您感到有些惊讶的是,您遇到了这样的错误。我原以为你会得到 "ORA-21000: error number argument to raise_application_error of 1 is out of range"
,正如可以证明的那样 in this SQL Fiddle。这可能是因为你在最后一个分号后有点狡猾。当我在文本编辑器中查看它时,它以十六进制显示 space,但是当我将它复制到 SQL Fiddle 时判断它的显示方式可能不是。它也可能是 Stack Exchange 渲染引擎的产物。
顺便说一句,0001
不是 有效的 Oracle 错误代码; 00001
是唯一约束违规,将被声明为 -00001
(注意减号)。
但是,我不会这样做。触发器在使用时会产生额外的开销,并且会混淆可以在数据库中声明的约束。级联触发器也总是存在危险,这会使您的数据模型极其复杂。
更简单的方法是声明您的 POSTCODE
列最多为 8 characters/bytes(由您决定)并在该列上添加一个 check constraint确保邮政编码的长度为 6 个字符(或字节)或更长。这将您需要的逻辑嵌入到 table 的结构中(因此嵌入到 Oracle 的元数据中),使查看正在发生的事情变得容易得多。
如果您要将 table 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)