カーソルで集合関数を使った場合のEXCEPTION

このQ&Aのポイント
  • PL/SQLの質問です。カーソルを使用して集合関数を実行している場合、INVALID ERRORのEXCEPTIONを使用して数値でないデータに対処する方法を知りたいです。
  • カーソルで集合関数エラーが発生したレコードのみEXCEPTIONで扱い、それ以外のデータはきちんとチェックする方法について教えてください。
  • カーソル内で集合関数を使用していますが、一部のレコードでエラーがあっても全てのレコードがエラーと判断されてしまいます。カーソルで集合関数エラーが発生したレコードのみEXCEPTIONで処理し、それ以外のデータは正確にチェックする方法を教えてください。
回答を見る
  • ベストアンサー

カーソルで集合関数を使った場合のEXCEPTION

PL/SQLの質問です。 declare でカーソルを宣言し、その中で集合関数を使用しています。(sum) CHAR型の項目に対して掛けるので、数値でないものが入っていた場合のために INVALID ERRORのEXCEPTIONをつけました。 BEGINE  FOR rec IN cur_test  LOOP   ----  END LOOP; EXCEPTION  WHEN INVALID_NUMBER THEN   ------ END; しかし、このやりかただと、一部のレコードでエラーがあっても、 全てのレコードがエラーと判断されてしまいます。 カーソルで集合関数エラーが発生したレコードのみEXCEPTIONで扱い、 それ以外のデータはきちんとチェックしたいのですが、 そのような方法はあるでしょうか? よろしくお願いします。

  • Oracle
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • _lemon
  • ベストアンサー率100% (2/2)
回答No.1

こんにちは。 表(TEST)を以下とします。 ************************************* SQL> desc test 名前 型 -------- COL1 CHAR(1) COL2 CHAR(1) ************************************* データは、こんなかんじ。 ************************************* SQL> select * FROM TEST ; COL1 COL2 - - 1 1 1 2 2 3 2 4 3 1 3 a 4 9 ************************************* ここで、COL1で、GROUP BYして、COL2のSUMを取る。 ただし、COL2には、数値以外があり(上の例では「a」)とします。 いきなり、全部をカーソルとすると、カーソルのレコードセットを作る時点でエラーとなるので、 (1)COL1をGROUP BYするカーソルを準備 (2)COL1を読んで、その値で、COL2をSUM ここで、数値例外が出ても、継続するために、(2)の部分を別ブロックとします。 こんな感じでしょうか。 ********************************************* DECLARE CURSOR cur_test IS SELECT COL1 FROM TEST GROUP BY col1 ; v_sum NUMBER; flg BOOLEAN ; BEGIN FOR rec IN cur_test LOOP flg := TRUE ; /*****************************************/ BEGIN SELECT SUM(COL2) INTO v_sum FROM TEST WHERE COL1 = rec.col1 ; EXCEPTION WHEN INVALID_NUMBER THEN flg := FALSE ; END; /*********************************************/ IF ( flg ) THEN dbms_output.put_line('v_sum=' || v_sum); END IF ; END LOOP ; END; / ********************************************* 直接の回答になってなくて、もうしわけないですが、参考になられましたでしょうか?

boroichi
質問者

お礼

それです! やり方つかめました。ありがとうございました。

関連するQ&A

  • カーソルについて

    カーソルってオープン時に該当データの全レコードセットを取得するんでしょうか?。 PL/SQLでVIEWのカーソルをオープンし、ループ処理を行っているんですが、処理速度からして1フェッチごとに毎回SELECT文を発行しているように見受けられます・・・。 ソースはこんな感じです↓。 declare cursor cur_tb_1 is select * from ビュー; begin for rec_tb_1 in cur_tb_1 loop ...処理いろいろ end loop; end; また、このようなケースの場合、VIEWのSELECT結果を一時テーブルにINSERTし、そのテーブルをSELECTするカーソルを使用するほうが 作法的によいのでしょうか?

  • PL/SQLにてカーソル名を変数に

    PL/SQLにて、カーソル名を変数にしたいのですが、どうすればよいのでしょうか? 具体的には以下のとおりです。 DECLARE CURSOR Cur1 IS SELECT K1,K2 FROM EMP; BEGIN FOR Cur_Rec1 IN Cur1     Cur_Rec1.K1 DBMS_OUTPUT.PUT_LINE(Cur_Rec1.K1); ★ END LOOP; END; ★の部分の「Cur_Rec1.K1」を「Cur_Rec1.K2」として、置き換えて使用したいのです。(2回書きたくない) 初心者で、申し訳ないです。どうか、ご教授ください。

  • ORA-06502のエラー

    以下のPL/SQLを実行すると、ORA-06502:数値または値のエラーとでます。途中までは、INSERTできるのですが、IF文の180個目くらいでエラーになります。そのあたりをCur1の宣言時にWhereで指定するとうまくいきます。 DECLARE CURSOR Cur1 IS SELECT MOJI FROM A_TBL ; CNT NUMBER(10); KAKKO_FL NUMBER(1); BEGIN CNT := 0; KAKKO_FL :=0; FOR Cur_Rec1 IN Cur1 LOOP FOR S IN 1 .. LENGTH(Cur_Rec1.MOJI) LOOP IF(ASCII(SUBSTR(Cur_Rec1.MOJI,S,1)) = 33129) THEN /*33129は'('*/ EXECUTE IMMEDIATE ' INSERT INTO EDD.test1116 VALUES( ''' || Cur_Rec1.MOJI || ''' ) '; END IF; END LOOP; END LOOP; END; なにがなんだか、さっぱりわからないので、どうか、ご教授ください。

  • カーソルループ内部でログを出力

    DECLARE CURSOR EMP_CUR IS SELECT SALARY FROM EMP WHERE DEPT_NO = 10 FOR UPDATE; BEGIN FOR EMP_REC IN EMP_CUR LOOP DBMS_OUTPUT.PUT_LINE( '変更前:' || EMP_REC.SALARY ); --SALARYが2500以下なら100を加える IF EMP_REC.SALARY < 2500 THEN UPDATE EMP SET SALARY = SALARY + 100 WHERE CURRENT OF EMP_CUR; DBMS_OUTPUT.PUT_LINE( '処理件数:' || SQL%ROWCOUNT ); END IF; DBMS_OUTPUT.PUT_LINE( '変更後:' || EMP_REC.SALARY ); END LOOP; END; / 上記のようなSQLで、 変更前のSALARYと変更後のSALARYを出力したいのですが、 変更前と変更後のEMP_REC.SALARYで、同じ値が出力されました。 処理の前後でSELECTする事は可能であると思いますが、 カーソル内でまとめて行いたいです。 カーソル内でIF文の前後の値を出力する事は可能でしょうか? また、もう1点質問があります。 それは、SALARYの値が、どちらも更新された値が出力される事についてです。 例:DEPT_IDが10で、SALARYが1000の従業員が居た場合。   変更前:1100   変更後:1100 EMP_REC.SALARYの値が、DECLAREで定義されたカーソルのデータならば、 1000が出力されると考えたのですが、 どちらも更新後の値が出力されるのは何故でしょうか? お手数をお掛け致しますが、よろしくお願い致します。

  • PL/SQLについての質問です。

    PL/SQLについての質問です。 カーソルデータ(emp_rec(i))を、TABLE変数(emp_ins(i))に代入して、代入されたTABLE変数を使用して、DML処理を行うことは可能ですか? エラーを解読し対処を行っても、エラーが発生してしまいます。 どうか、ご教授お願いします。 下記を実行すると、下記エラーが発生します。 -実行結果------------------------------------ DECLARE * 行1でエラーが発生しました。: ORA-06502: PL/SQL: 数値または値のエラーが発生しました ORA-06512: 行127 -エラー番号解読----------------------------------------- ●エラー名: PL/ SQL: 数値または値のエラーstring が発生しました ●原因: 算術、数値、文字列、変換または制約エラーが発生しました。たとえば、NULL 値をNOT NULL で宣言した変数に割り当てようとした場合、または100 以上の整数をNUMBER( 2) で宣言した変数に割り当てようとした場合にこのエラーが発生します ●処置:値が制約違反をしないように、データ、操作方法または宣言方法を変更してください。 -ソース------------------------------------ DECLARE --カーソル定義 CURSOR emp_cur IS SELECT a,b,c FROM emp TYPE emptabtype IS TABLE OF emp%ROWTYPE INDEX BY PLS_INTEGER; emp_rec emptabtype; /* 処理対象データ格納変数 */ -- insert作業用 emp_ins emptabtype; ins_count NUMBER := 1; BEGIN /* empカーソルオープン・フェッチ・クローズ */ OPEN emp_cur; FETCH emp_cur BULK COLLECT INTO emp_rec; CLOSE emp_cur; /* (挿入)処理対象のデータを、処理対象データ格納変数に格納する。 */ FOR i IN emp_rec.FIRST..emp_rec.LAST LOOP --挿入するレコードを格納 emp_ins(ins_count) := emp_rec(i); ins_count := ins_count + 1; END LOOP; /* DML処理 */ -- 挿入する FOR count_ins IN emp_ins.FIRST..emp_ins.LAST LOOP INSERT INTO temp VALUES(emp_ins(count_ins).a ,emp_ins(count_ins).b ,emp_ins(count_ins).c); END LOOP; COMMIT; END; /

  • PL/SQLの例外処理で出力しないようにしたい

    いつもお世話になっております。 PL/SQLの例外処理で分からないところがあるのですが どなたかお分かりになる方がいましたら、 教えていただけないでしょうか?? コーディングの悩んでる部分だけしか貼れないのですが↓↓ BEGIN FOR c_rec IN c_cur LOOP /*事業者テーブルからデータを探す*/ BEGIN SELECT cust_id, unit_sec INTO v_cust_id, v_unit_sec FROM m_cust WHERE op = c_rec.call AND vc = c_rec.isdn; EXCEPTION WHEN TOO_MANY_ROWS THEN v_err_msg := '該当業者が複数見つかりました'; WHEN NO_DATA_FOUND THEN       ★★ END; ★★のところで、何も見つからないエラーの場合、 何も文字を出力しないで、カーソルFOR LOOPの 次のレコードに行ってほしいのです。 何かしらエラー処理をしないと、プロシージャが正常に 完了してくれないので今はエラー番号を表示させているのですが ここに何を記入すればよいでしょうか?? よろしくお願いいたします。

  • PL/SQLでカーソルを指定する方法

    以下のSQL文で、 あるストアドプロシージャを作成し、その引数の値を WHERE句の検索条件に取ってカーソルを宣言したいので すが、どうやってもエラーが出ます。結果として カーソルで格納したデータを呼び出し元に返したいの ですが…。下記の文は間違ってますか? CREATE OR REPLACE PROCEDURE ss( quote IN NUMBER result OUT CHAR ) IS CURSOR cur IS SELECT empname FROM emp WHERE empno = quote; result cur%rowtype; BEGIN OPEN cur; LOOP FETCH cur INTO result; ~ END; どうかよろしくお願いします。

  • カーソルフェッチにて、最終レコードが重複します

    いつもお世話になります。 WindowsVista Oracle10gの環境にて、以下のようにPL/SQLを作成し、結果を確認しましたが、最終レコードが重複してしまいます。 SQL文が悪いのかと思い、切り出してSQLPlusで確認しましたが正しく返ってきます。 DECLARE type cur_type is ref cursor; souk_cur cur_type; vSql varchar2(2000); BEGIN vSql := ' select ~ from TableA' open souk_cur for vSql; loop fetch souk_cur into p1; dbms_output.putline(p1) exit when souk_cur%notfound; end loop; close souk_cur; END; / <結果> 1 あああ 2 いいい 3 ううう 3 ううう 試しにorder byで並べ替えると、 <結果> 3 ううう 2 いいい 1 あああ 1 あああ と、やはり最終レコードが重複します。 どなたかご存知の方おられましたらご教授願えませんでしょうか? 宜しくお願い致します。

  • カーソルで取得した項目のサイズについて質問です。。

    カーソルで取得した項目のサイズについて質問です。。 SELECTした項目のサイズが下記の場合、 レコード格納変数.Cの最大サイズは(14)で、それ以上のバイト数値を代入すると エラーになると思ったのですが、エラーになりませんでした。(最大28バイトになった) レコード格納変数の取得した項目サイズは何で決まってくるのでしょうか? この項目を別テーブルのVARCHAR(20)の項目へ設定しようと思っているのですが、 理由がわからないので、このままでいいのか、サイズを考慮した設計にするべきか困っています。 <oracle 9i> TABLE1{A VARCHAR2(4), B VARCHAR2(10)} DECLARE  CURSOR カーソル変数 IS SELECT A||B AS C FROM TABLE1;  レコード格納変数 カーソル変数%ROWTYPE; BEGIN  OPEN カーソル変数  LOOP   FETCH カーソル変数 INTO レコード格納変数;   EXIT WHEN カーソル変数%NOTFOUND;    :    レコード格納変数.C := VARCAHR2(15) --代入可能?    :    INSERT 項目1 VARCHAR(20) TABLE2 レコード格納変数.C;    :  END LOOP  CLOSE カーソル変数 END;

  • PL/SQLで変数へ値の代入

    PROCEDURE TEST(PI_ABC IN A_TABLE.A_CODE%TYPE) IS CURSOR CUR IS SELECT A_CODE FROM A_TABLE; BEGIN --抽出したデータを代入 FOR REC_CUR IN CUR LOOP PI_ABC := REC_CUR.A_CODE; END LOOP; 上記のコードを実行すると ORA-06502:数値または値のエラー PL/SQL: 文字列バッファが小さすぎます。 とエラーが出ます。 このプロシージャを呼び出す時にも同じテーブル同じ項目を渡しています。 同パッケージ内で同じ事をやっているのに特定のプロシージャだけ 上記のエラーが出てしまいます。 環境:Windows2003Server oracle9i