如何在程序中检查参数值是否存在?

时间:2012-11-25 06:36:34

标签: sql stored-procedures plsql

以下是使用2个参数的过程:customer_code和pay_amount。 该过程按预期工作,但是当我输入错误的cus_code时,我得到错误而不是我的自定义检查:

ORA-01403: no data found
ORA-06512: at "XXXXX.CUST_PAY", line 19
ORA-06512: at line 2

程序:

CREATE OR REPLACE PROCEDURE cust_pay (temp_ccode IN NUMBER, pay_amount IN NUMBER)AS
  BEGIN
    DECLARE 
    Value_check NUMBER;
    cbalance NUMBER;
      BEGIN
          SELECT Count(cus_code) 
          INTO value_check
          FROM customer
          WHERE cus_code = temp_ccode;

          IF value_check IS NULL THEN
              Dbms_Output.put_line('the value was not FOUND');
          ELSE
              UPDATE customer
              SET cus_balance = cus_balance - pay_amount
              WHERE cus_code = temp_ccode;

              SELECT cus_balance 
              INTO cbalance
              FROM customer
              WHERE cus_code = temp_ccode;

                IF cbalance < 0 THEN
                    Dbms_Output.put_line('The client owes us ' || cbalance);
                ELSE
                    Dbms_Output.put_line('Customer new balance is ' || cbalance);
                END IF;
        END IF;
     END;
  END;

我做错了什么?我是客人,我需要在发出SELECT请求之前检查该值,对吗?

4 个答案:

答案 0 :(得分:2)

您的问题实际上是由您的支票引起的:

  SELECT COUNT (cus_code)
    INTO value_check
    FROM customer
   WHERE cus_code = temp_ccode;

以上查询将从不返回NULL,这是您要检查的内容。如果表中的值与参数temp_ccode不匹配,则value_check将为0.这反过来意味着您的IF语句不正确,这会导致您的代码稍后出现错误。

虽然有一种更简单,更有效的方法。您可以使用SQL%ROWCOUNT查看更新对受影响的行数。如果返回值为0,则表示您的客户不存在。

create or replace procedure cust_pay (
     Ptemp_ccode in number
   , Ppay_amount in number
     ) is

   l_balance number;

begin

   update customer
      set cus_balance = cus_balance - Ppay_amount
    where cus_code = Ptemp_ccode;

   if SQL%ROWCOUNT = 0 then
      dbms_output.put_line('The customer was not found.');
   else
      select cus_balance 
        into l_balance
        from customer
       where cus_code = temp_ccode;

      if l_balance < 0 then
         dbms_output.put_line('the client owes us ' || l_balance);
      else
         dbms_output.put_line('customer new balance is ' || l_balance);
      end if;
   end if;

end;

这里不需要处理select... into ...中的NO_DATA_FOUND异常,因为您已经保证UPDATE语句存在cus_code

请注意我所做的其他更改:

  1. 参数和变量的不同命名约定,因此在代码中清楚显示哪个。
  2. 删除额外的嵌套PL / SQL块,这是不必要的。
  3. 一般来说,你不应该在PL / SQL块中使用dbms_ouput.put_line,因为你在那里看看发生了什么。它适用于调试过程,但在生产代码中相当无用。

    也可以使用RETURN statement来避免嵌套的IF语句,我认为这使代码更清晰,更容易阅读;虽然这是一个判断电话。

    create or replace procedure cust_pay (
         Ptemp_ccode in number
       , Ppay_amount in number
         ) is
    
       l_balance number;
    
    begin
    
       update customer
          set cus_balance = cus_balance - Ppay_amount
        where cus_code = Ptemp_ccode;
    
       if SQL%ROWCOUNT = 0 then
          return;
       end if;
    
       select cus_balance 
         into l_balance
         from customer
        where cus_code = temp_ccode;
    
       if l_balance < 0 then
          dbms_output.put_line('The client owes us ' || l_balance);
       else
          dbms_output.put_line('New balance is ' || l_balance);
       end if;
    
    end;
    

    所有这些都假定您的CUSTOMER表在cus_code上是唯一的。

答案 1 :(得分:2)

您的代码的更正版本在此处:

CREATE OR REPLACE PROCEDURE cust_pay (temp_ccode IN NUMBER, pay_amount IN NUMBER) AS
   Value_check NUMBER;
   cbalance NUMBER;
BEGIN
   SELECT Count(cus_code) 
   INTO value_check
   FROM customer
   WHERE cus_code = temp_ccode;

   IF value_check = 0 THEN
      Dbms_Output.put_line('the value was not FOUND');
   ELSE
      UPDATE customer
      SET cus_balance = cus_balance - pay_amount
      WHERE cus_code = temp_ccode
      RETURNING cus_balance
      INTO cbalance;

      IF cbalance < 0 THEN
         Dbms_Output.put_line('The client owes us ' || -cbalance);
      ELSE
         Dbms_Output.put_line('Customer new balance is ' || cbalance);
      END IF;
   END IF;
END;

答案 2 :(得分:2)

Egor Skriptunoff刚刚发布了一个intriguing answer,我不想对这个想法说任何功劳,所以我将其作为一个不同的答案发布。它实际上可以在一个声明中完成所有事情。

基于我在其他答案中提倡的原则,如果你更新一个不存在的客户的余额并不重要,你可以结合我自己和Egor的答案来提出这个:

create or replace procedure cust_pay (
     Ptemp_ccode in number
   , Ppay_amount in number
     ) is

   l_balance number;

begin

   update customer
      set cus_balance = cus_balance - Ppay_amount
    where cus_code = Ptemp_ccode
   returning cus_balance
     into l_balance;

   if SQL%ROWCOUNT = 0 then
      dbms_output.put_line('The customer was not found.');
   elsif l_balance < 0 then
      dbms_output.put_line('The client owes us ' || l_balance);
   else
      dbms_output.put_line('New balance is ' || l_balance);
   end if;

end;

在一个声明中做所有事情的好处是速度的提高。再次,您不必担心NO_DATA_FOUND异常,因为您只进行了更新。

我在之前的回答中说的所有内容仍然适用,count(*)中的select... into...永远不会返回null,总是一个数字。

答案 3 :(得分:0)

您可以在sql查询之前检查以验证参数值

另一种方法是使用EXCEPTION NO_DATA_FOUND

CREATE OR REPLACE PROCEDURE cust_pay (temp_ccode   IN NUMBER,
                                      pay_amount   IN NUMBER,errcode OUT NUMBER)
AS
BEGIN
   DECLARE
      Value_check   NUMBER;
      cbalance      NUMBER;
   BEGIN
      SELECT COUNT (cus_code)
        INTO value_check
        FROM customer
       WHERE cus_code = temp_ccode;

      IF value_check IS NULL
      THEN
         DBMS_OUTPUT.put_line ('the value was not FOUND');
      ELSE
         UPDATE customer
            SET cus_balance = cus_balance - pay_amount
          WHERE cus_code = temp_ccode;

         SELECT cus_balance
           INTO cbalance
           FROM customer
          WHERE cus_code = temp_ccode;

         IF cbalance < 0
         THEN
            DBMS_OUTPUT.put_line ('The client owes us ' || cbalance);
         ELSE
            DBMS_OUTPUT.put_line ('Customer new balance is ' || cbalance);
         END IF;
      END IF;
   END;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      DBMS_OUTPUT.put_line ('no data***' || SQLERRM);
      errcode := 1;
END;