3

Oracle でストアド プロシージャを作成しました。プロシージャはエラーなしで正常にコンパイルされます。この手順には、3 つのテーブル「TBLHOTEL」、「TBLHOTELDETAIL」、および「TBLHOTELFARE」を更新する 3 つの UPDATE クエリがあります。

すべての Update ステートメントの後、成功した挿入クエリの数を取得するために、変数 successCnt1 がインクリメントされます。最後に、successCnt1 が successCnt に割り当てられ、最終結果が格納されます。例外が発生した場合、任意のクエリで、挿入が発生しないことを示すために 0 に設定されます。

問題は、例外が発生しておらず、データベースの更新も行われていないことです。

これが私のコードです:

スキーマ:

TBLHOTEL スキーマ: {DATE1 (DATE) , ACROOMS (NUMBER) , NACROOMS (NUMBER), HOTELID (VARCHAR2(10)) }

TBLHOTELFARE スキーマ: {HOTELID (VARCHAR2(10)), CLASS (VARCHAR2(5)), FARE (NUMBER)}

TBLHOTELDETAIL スキーマ: {HOTELID (VARCHAR2(10)) , PLACE (VARCHAR2(15)) , HOTELNAME (VARCHAR2(15)) }

手順:

CREATE OR REPLACE PROCEDURE TableUpdateByParameter (acrooms   in number,
                                           nacrooms  in number,
                                           date1      in date,
                                           hotelid   in varchar2,
                                           fare in number,
                                           place in varchar2,
                                           hotelname in varchar2,
                                           class in varchar2,
                                           successCnt  out number) IS

successCnt1 number(6) NOT NULL := 0;
rowUpdated1 number(6) NOT NULL := 0;
rowUpdated2 number(6) NOT NULL := 0;
rowUpdated3 number(6) NOT NULL := 0;

BEGIN
  SAVEPOINT before;

  UPDATE tblhotel
     SET acrooms = acrooms, nacrooms = nacrooms
   WHERE date1 = (to_date(date1, 'mm/dd/yyyy'))
     AND hotelid = 'hotelid' ;

rowUpdated1 := SQL%RowCount;
successCnt1 := successCnt1 + 1;

   dbms_output.put_line('Successful Insertion tblhotel. count ='||successCnt1);
   dbms_output.put_line('Successful Insertion tblhotel. Row Updated ='||rowUpdated1);

  UPDATE tblhoteldetail
 SET place = 'place', hotelname = 'hotelname'
   WHERE hotelid = 'hotelid' ;

rowUpdated2 := SQL%RowCount;
successCnt1 := successCnt1 + 1;

dbms_output.put_line('Successful Insertion tblhoteldetail. count ='||successCnt1);
dbms_output.put_line('Successful Insertion tblhoteldetail. Row Updated= '||rowUpdated2);

  UPDATE tblhotelfare
     SET fare = fare
   WHERE hotelid = 'hotelid' 
     AND class = 'class';

rowUpdated3 := SQL%RowCount;
successCnt1 := successCnt1 + 1;
successCnt := successCnt1;

 COMMIT;

 dbms_output.put_line('Successful Insertion tblhotelfare. count ='||successCnt);
dbms_output.put_line('Successful Insertion tblhotelfare. Row Updated= '||rowUpdated3);

EXCEPTION
  WHEN Others THEN
    successCnt1 := 0;
    successCnt := successCnt1;
    dbms_output.put_line('An error has occured. count ='||successCnt);

    ROLLBACK TO before;

END;

招集声明

DECLARE 
 C  number;

BEGIN

   TableUpdateByParameter (140,200,TO_DATE('03/24/2013','MM/DD/YYYY'),'H1',3000,'GANGTOK','TRIPTI','AC',C);
END;

DBMS 出力:

Successful Insertion tblhotel. count =1
Successful Insertion tblhotel. Row Updated =0
Successful Insertion tblhoteldetail. count =2
Successful Insertion tblhotel. Row Updated =0
Successful Insertion tblhotelfare. count =3
Successful Insertion tblhotel. Row Updated =0

問題を特定するのを手伝ってください。追加情報が必要な場合は、お知らせください。

4

3 に答える 3

7

UPDATEステートメント機能していますが、ログに示されているように 0 行を更新しています ( ) Row Updated =0。これはエラーではありません。更新によって where 句が評価され、一致する行が 0 件見つかり、変更が実行されません。Oracle では、where 句のどの行とも一致しない更新でも成功します。

なぜそれが起こるのですか?最初の更新を見てみましょう:

UPDATE tblhotel
   SET acrooms = acrooms, nacrooms = nacrooms
 WHERE date1 = (to_date(date1, 'mm/dd/yyyy'))
   AND hotelid = 'hotelid' ;

hotelidパラメータとして渡された値を持つ列を持つ行を更新したいと思います。これにはいくつかの問題があります。

  • まず、列とパラメーターを比較するのではなく、列と定数を比較します。パラメータは引用符を使用しません。定数 (VARCHAR2) が行います。
  • 次に、列と同じ名前のパラメーターを呼び出さないでください。これにより、混乱が生じ、変数のシャドウイングが発生する可能性さえあります。スキーマでどの列も使用しない接頭辞を使用することをお勧めします。パラメータの一般的なプレフィックスの 1 つにp_.
  • 最後に、パラメーターが適切な型である場合、変換関数は必要ありません (パラメーターp_date1が日付型であるため、関数は必要ありませんto_date)。

パラメータの名前を と に変更するp_hotelidp_date1、ステートメントは次のようになります。

UPDATE tblhotel
   SET acrooms = acrooms, nacrooms = nacrooms
 WHERE date1 = p_date1
   AND hotelid = p_hotelid;

この場合、混乱や変換エラーの可能性はありません。


無関係なメモについて:

于 2013-03-28T13:36:32.543 に答える
1

がデータベース内の列である場合hotelid、名前をオーバーロードしてプロシージャの引数の名前として使用したくないことはほぼ確実です。これを行うと、SQL ステートメントでのパラメーターの使用がかなり複雑になります。ほとんどの人は、この 2 つを区別するために何らかの規則を作成します。p_私は、比較的一般的な慣習であるa をパラメーター名にプレフィックスとして付けることを好みます。

CREATE OR REPLACE PROCEDURE TableUpdateByParameter (p_acrooms   in number,
                                           p_nacrooms  in number,
                                           p_date1      in date,
                                           p_hotelid   in varchar2,
                                           p_fare in number,
                                           p_place in varchar2,
                                           p_hotelname in varchar2,
                                           p_class in varchar2,
                                           p_successCnt  out number) 
IS

SQLステートメントは次のようになります

 WHERE tblhoteldetail.hotelid = p_hotelid

本当にパラメーター名をオーバーロードしたい場合は、パラメーター名の前にプロシージャ名を付ける必要があります。しかし、それは通常、うっかり次のようなコードを書いてしまうので、悲しみが尽きることはありません。

 WHERE tblhoteldetail.hotelid = hotelid

うっかりテーブルのすべての行を更新してしまいます。

于 2013-03-28T13:39:34.370 に答える
0

それぞれのwhereステートメントは次のようになります。

AND hotelid = 'hotelid'

これにより、テーブルの hotelid 列が、proc に渡される値ではなく、その文字列リテラル「hotelid」と毎回照合されます。

それらにパラメーターを参照させるには、次のようなものを使用する必要があります。

AND tblhotel.hotelid = TableUpdateByParameter.hotelid

左側がテーブルの列で、右側が proc パラメータです。

別の方法は、すべてのパラメーターの前に「p」を付けるという命名規則を使用して、次を使用できるようにすることです。

AND tblhotel.hotelid = photelid
于 2013-03-28T13:30:21.170 に答える