0

以下是使用 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

4 回答 4

2

您的问题实际上是由您的检查引起的:

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

上面的查询永远不会返回 NULL,这是您正在检查的内容。如果表中没有与参数匹配的值,temp_ccodevalue_check将为 0。这反过来意味着您的 IF 语句不正确,这会导致您稍后在代码中出现错误。

不过,有一种更简单、更有效的方法。您可以使用SQL%ROWCOUNT找出您的 UPDATE 影响了多少行。如果返回值为 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 块,这是不必要的。

一般来说,您永远不应该dbms_ouput.put_line在 PL/SQL 块中使用,因为您必须在那里才能看到发生了什么。这对于调试过程很好,但在生产代码中相当无用。

也可以使用RETURN 语句来避免嵌套的 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.

于 2012-11-25T09:30:38.043 回答
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;
于 2012-11-25T10:00:00.123 回答
2

Egor Skriptunoff 刚刚发布了一个有趣的答案,我不想为这个想法声称任何功劳,所以我将其发布为一个不同的答案。实际上可以在一个语句中完成所有操作。

根据我在其他答案中提倡的原则,如果您更新不存在的客户的余额并不重要,您可以结合我自己的答案和 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(*)aselect... into...永远不会返回 null,总是一个数字。

于 2012-11-25T10:14:25.703 回答
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;
于 2012-11-25T07:04:03.987 回答