0

以下は、customer_codeとpay_amountの2つのパラメーターを使用する手順です。手順は期待どおりに機能しますが、間違った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

コードの修正バージョンは次のとおりです。

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が興味をそそる回答を投稿したばかりで、そのアイデアの功績を認めたくないので、これを別の回答として投稿します。実際には、1つのステートメントですべてを実行することは可能です。

私の他の回答で提唱されている、存在しない顧客の残高を更新するかどうかは問題ではないという原則に基づいて、私自身の回答と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;

1つのステートメントですべてを実行することの利点は、速度が向上することです。ここでも、更新のみを行っているため、NO_DATA_FOUND例外について心配する必要はありません。

以前の回答で私が言ったことはすべて当てはまりますcount(*)。aselect... into...はnullを返すことはなく、常に数値を返します。

于 2012-11-25T10:14:25.703 に答える
2

あなたの問題は実際にはあなたのチェックが原因です:

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

上記のクエリはNULL を返すことはありません。これは、チェックしているものです。テーブル内の値がパラメーターと一致しない場合、 はtemp_ccode0value_checkになります。これは、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;

UPDATE ステートメントによって存在するselect... into ...ことが既に保証されているため、ここで NO_DATA_FOUND 例外を処理する必要はありません。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 に答える
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 に答える