2016-06-09 84 views
1

我需要编写这样一个触发器来检查人员姓名,如果他们的姓名中有任何数字,将会打印出他/她的ID。检查VARCHAR2是否仅包含使用触发器的字母表

我有现在:

set SERVEROUTPUT ON 
create or replace trigger BeforeUpdate 
Before insert on customer 
for each row 

declare 
n varchar2(10); 
counter number; 
nextR number:=0; 

begin 
select count(id_customer) into counter from customer; 

LOOP 
nextR:= nextR +1; 
select cname into n from customer where id_customer = nextR; 
if n not like '%[0-9]%' then 
DBMS_OUTPUT.PUT_LINE(nextR || ' has incorrect name'); 
end if; 
exit when nextR = counter; 
end loop; 
end; 
/

它编译,当我试图触发此触发它什么也不做。

我将不胜感激任何帮助。

回答

1

使用正则表达式来获得您的结果。

就你而言,如果你在n中得到一个数字,你的if子句应该被执行。

所以,

if regexp_replace(n,'[^[:digit:]]') IS NOT NULL then  
DBMS_OUTPUT.PUT_LINE(nextR || ' has incorrect name'); 
end if 

看来你也尝试使用正则表达式的数字。但是,您的代码正在搜索的是其中包含[0-9]的字符串。像Bat[0-9]Man,这不是你想要的结果。

在我的代码中,无论给定名称中的数字是否被替换。如果名称不包含任何数字,则正则表达式将返回null。如果在任何地方有任何数字,表达式将返回这些数字。

正在发生的事情在这里你可以分析以下查询是为了更好地抓:

select regexp_replace(cname,'[^[:digit:]]') OUTP, cname from customer; 

编辑:

这不是你如何写一个触发!

每次插入将发生时触发器将被触发。你不需要柜台。您需要使用:新参考

set SERVEROUTPUT ON 
create or replace trigger update or 
Insert on customer 
for each row 

begin 
if regexp_replace(:NEW.cname,'[^[:digit:]]') IS NOT NULL then 
DBMS_OUTPUT.PUT_LINE(nextR || ' has incorrect name'); 
end if; 
end; 
/
+0

不幸的是,这是行不通以及 但现在我h我想知道我应该使用什么。 非常感谢 – Yun8483

+0

@ Yun8483,它的确适用于我的示例。好的,继续尝试:-)我所做的调整将捕获像Bat9Man,Bat9Man1等等的东西。 –

+0

@ Yun8483,编辑 –

1

这是REGEXP_LIKE()的工作! '\d'的正则表达式匹配一个数字。

SQL> with tbl(id, name) as (
     select 1, 'Batman' from dual union 
     select 2, 'Robin1' from dual union 
     select 3, 'Supe4rman' from dual union 
     select 4, '3Joker' from dual 
    ) 
    select id, name bad_name 
    from tbl 
    where regexp_like(name, '\d'); 

     ID BAD_NAME 
---------- --------- 
     2 Robin1 
     3 Supe4rman 
     4 3Joker 

SQL> 

如果你的目标是去掉在路上的数字(不过要小心,一个公司真正能有像第三级通讯公司或3Com公司名称中的数字,如果它是一个人的可能性较小,但这些天谁知道)这是未经测试:

CREATE OR REPLACE TRIGGER customer_bu 
BEFORE INSERT OR UPDATE 
ON customer 
REFERENCING NEW AS NEW OLD AS OLD 
FOR EACH ROW 
BEGIN 
    -- If the new name contains a digit, strip it. 
    if regexp_like(:new.name, '\d') then 
    :new.name := regexp_replace(:new.name, '\d', NULL); 
    end if; 

END customer_bu; 
/
+0

我不是为什么,但在我的情况下,它反之亦然。我认为这是因为我的代码。我会尝试修复和实施这种方法。万分感谢。 – Yun8483

+0

@ Yun8483 - 请参阅我的更新。 –

+0

哦,你想在名字中的数字?我可能会颠倒过来。 –

2

有一对夫妇的代码中的问题:

  • 在触发器使用dbms_output并没有真正意义;通常,INSERT将由不处理控制台输出的客户端代码执行。 明智的是提出异常。
  • 您不需要在触发代码中执行SELECT。事实上,这样做通常或者是多余的,或者引起表格变异错误。相反,使用:新:旧指已插入
  • (未成年人)行的值命名之前,INSERT触发器BeforeUpdate有点混乱
  • 使用正则表达式进行认真测试此业务规则(;正则表达式规则这种事情)

总之,这里的固定版本(未经测试,我没有可用于测试一个Oracle实例现在):

create or replace trigger TR_BI_CUSTOMER 
Before insert on customer 
for each row 
begin 
    if regexp_like(:new.name, '.*[0-9].*') then 
    raise_application_error(-20001, 'Incorrect name: ' || :new.name); 
    end if; 
end; 
+0

@I_am_Batman Doh!多么愚蠢的错误,谢谢你指出这一点。固定。 –

+0

我不小心将这个触发器命名为BeforeUpdate,在更新触发器之前我可能正在考虑Abot,同时做这个事情并且毕竟忘了更改名称。我很抱歉。 我本来应该使用一个循环。 是的,我有使用select的突变,但我需要以某种方式修复它。 但是你的建议真的很有帮助。万分感谢。 – Yun8483

相关问题