【问题标题】:Handling an exception in pl/sql在 pl/sql 中处理异常
【发布时间】:2017-12-23 06:55:26
【问题描述】:

我正在使用 Oracle Forms 10g 构建一个 GUI,通过填写表单将用户添加到数据库。以下是我在Add User 按钮上的when-button-pressed 触发器上使用的代码:

代码:

declare
    firstname VARCHAR(15);
    lastname VARCHAR(15);
    usernameee VARCHAR(15);
    emailll VARCHAR(15);
    pass1 VARCHAR(15);
    pass2 VARCHAR(15);
    v varchar2(200);
begin
    firstname := :HOMEADMIN1.TXTFIRSTNAME;
    lastname := :HOMEADMIN1.TXTLASTNAME;
    usernameee := :HOMEADMIN1.TXTUSERNAME;
    emailll := :HOMEADMIN1.TXTEMAIL;
    pass1 := :HOMEADMIN1.TXTPASSWORD;
    pass2 := :HOMEADMIN1.TXTPASSWORD2;

    if firstname is null or lastname is null or usernameee is null or 
        emailll is null or pass1 is null or pass2 is null then
        message('Please fill all fields');
    else
        select Firstname into v from Person where Username = usernameee;
        if sql%found then
            message('This username is already taken');
        else
            select Firstname into v from Person where Email = emailll;
            if sql%found then
                message('This email is already taken');
            else
                insert into Person values (PersonSeq.nextval,firstname,lastname,usernameee,pass1,emailll,0,1);
                commit;
            end if;
        end if;
    end if;
end;

此代码检查是否所有输入 textboxes 都已填充(有效),然后它必须检查输入的 usernameemail 是否已被使用。代码编译得很好,但是当我输入任何emailusername 时,我得到一个error 01403,这表明我必须处理NO_DATA_FOUND exception。 你能告诉我如何在我的代码中做到这一点吗?我被卡住了,因为我有 2 个条件(查询)需要处理,但我不知道如何处理。任何帮助将不胜感激。

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    您感兴趣的行是获取“名字”的 SELECT 语句(具有不同的条件 - 一次通过用户名,然后通过电子邮件)。

    一种方法是使用聚合函数,例如MAX:

    select max(Firstname) into v from Person where Username = usernameee;
    

    这样做不会引发 NO-DATA-FOUND。

    不过,这只是一个不错的解决方法。正确的方法是正确处理异常。为此,您需要将这些 SELECT 语句包含在它们自己的 BEGIN-EXCEPTION-END 块中,例如:

    else
      -- First, check whether USERNAME is taken:
      begin
        select firstname into v from person where username = usernameee;
    
        -- You don't need IF SQL%FOUND because - if SELECT returned a value, you'll
        -- get here anyway
        message('This username is already taken');
        raise form_trigger_failure;   --> this is Forms, isn't it?
    
        exception
        -- SELECT returned nothing and raised an exception
        when no_data_found then 
          -- do nothing; proceed to EMAIL validation
          null;
      end;
    
      -- Username is available (because previous RAISE didn't fire
      begin
        select firstname into v from person where email = emailll;
    
        message('This email is already taken');
        raise form_trigger_failure;
    
      exception
        when no_data_found then
          null; 
      end;
    
      insert into person values (...);
      commit;
    end if;
    

    【讨论】:

    • 好吧,将“正常”行为(发现没有行似乎是默认行为)作为“例外”处理是一个品味问题。因此,我更喜欢第一种解决方案。
    • 如果我想使用第一个解决方案,select语句之后的条件应该是什么?
    • 如果您使用 MAX,那么您在初始消息中发布的代码将保持“原样”,无需更改 - 您只需将 MAX 添加到 SELECT 语句中。
    【解决方案2】:

    作为@Littlefoot 提供的解决方案的替代方案,您可以将每个验证拆分为自己的单独程序。主过程然后几乎没有逻辑。验证需求并插入或仅处理需求异常。所以:

    declare
        -- internal exceptions 
        not_all_fields_entered  exception; 
        user_name_already_taken exception; 
        email_already_taken     exception; 
    
        -- variables
        firstname VARCHAR(15);
        lastname VARCHAR(15);
        usernameee VARCHAR(15);
        emailll VARCHAR(15);
        pass1 VARCHAR(15);
        pass2 VARCHAR(15);
    
        -- validaion routines
        procedure validate_fields_entered
        is
        begin 
            if firstname is null or lastname is null or usernameee is null  
            or emailll is null or pass1 is null or pass2 is null  
            then
                raise not_all_fields_entered;
            end if;
        end validate_fields_entered; 
    
        procedure validate_user_name_not_taken
        is 
            user_name_count integer; 
        begin 
             select count(*) 
               into user_name_count
               from Person 
              where Username = usernameee
                and rownum < 2;
            if user_name_count = 1  
            then 
               raise user_name_already_taken;
            end if;
        end validate_user_name_not_taken; 
    
        procedure validate_email_not_taken
        is 
            email_use_count integer; 
        begin 
             select count(*) 
               into email_use_count
               from Person 
              where Email = emailll
                and rownum < 2;
            if email_use_count = 1  
            then 
               raise email_already_taken;
            end if;
        end validate_user_name_not_taken;     
    
    begin
        firstname := :HOMEADMIN1.TXTFIRSTNAME;
        lastname := :HOMEADMIN1.TXTLASTNAME;
        usernameee := :HOMEADMIN1.TXTUSERNAME;
        emailll := :HOMEADMIN1.TXTEMAIL;
        pass1 := :HOMEADMIN1.TXTPASSWORD;
        pass2 := :HOMEADMIN1.TXTPASSWORD2;
    
        -- do validations
        validate_fields_entered;
        validate_user_name_not_taken;
        validate_email_not_taken;
    
        -- all good insert the row 
        insert into Person values (PersonSeq.nextval,firstname,lastname,usernameee,pass1,emailll,0,1);
    
    exception 
        when not_all_fields_entered  then 
             message('Please fill all fields');
        when user_name_already_taken then  
             message('This username is already taken');
        when email_already_taken then  
              message('This email is already taken');
        when others then 
             log_error (....) ; 
             raise ;
    end;
    

    我知道这里没有指定,但请考虑维护。如果需求发生变化,需要什么: 1.如果没有采取验证电子邮件的格式是正确的。 2. 验证密码是否相同且满足复杂性规则。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多