tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルエラーになっても処理を続行させたい
記事No12828
投稿日: 2008/07/26(Sat) 11:47
投稿者eco
お世話になります。
VB6.0で開発しています。
質問ですが、わかる方いらっしゃいましたら教えてください。

Public Sub insert_tableC()
    Dim sSQL     As String
    Dim SQL      As String
    Dim objRst   As Object
    Dim objRst2  As Object
    Dim count    As Long
    Dim count2   As Long
    Dim fileNo   As Integer
    Dim errmsg   As String

    'オラクル接続
    Call set_ora
    
    'tableAより該当データSELECT
    sSQL = ""
    sSQL = sSQL & "   SELECT ABC "
    sSQL = sSQL & "     FROM tableA " & vbCrLf
    Set objRst = OraDatabase.DbCreateDynaset(sSQL, 0&)
    
    Do Until objRst.EOF
        With OraDatabase
            'バインド変数の定義
            .Parameters.Add "ABC", 0, ORAPARM_INPUT
            .Parameters("ABC").ServerType = ORATYPE_DATE
            .Parameters.Add "DEF", 0, ORAPARM_INPUT
            .Parameters("DEF").ServerType = ORATYPE_DATE
            
            .Parameters("ABC").Value = objRst.fields("ABC").Value
            
            'tableBより該当データSELECT
            sSQL = ""
            sSQL = sSQL & "   SELECT DEF "
            sSQL = sSQL & "     FROM tableB " & vbCrLf
            Set objRst2 = OraDatabase.DbCreateDynaset(sSQL, 0&)

            if objRst2.EOF then
                count1 = 1
            else
                count1 = 0
                .Parameters("DEF").Value = objRst2.fields("DEF").Value
            end if
            
            If count1 = 0 Then
                OraSession.begintrans
                '***INSERT処理***
                sSQL = ""
                sSQL = sSQL & " INSERT INTO tableC("
                sSQL = sSQL & "             ABC"
                sSQL = sSQL & "            ,DEF"
                sSQL = sSQL & "            ,TMSP"
                sSQL = sSQL & "      VALUES(" & vbCrLf
                sSQL = sSQL & "            ,:ABC "
                sSQL = sSQL & "            ,:DEF "
                sSQL = sSQL & "            ,SYSDATE)"
                .executeSQL (sSQL)
                OraSession.committrans
            End If
                
            'バインド変数の解放
            .Parameters.Remove "ABC"
            .Parameters.Remove "DEF"
            
        End With
        objRst.movenext    
    Loop

    'tableCよりデータ件数を取得
    sSQL = ""
    sSQL = sSQL & "   SELECT ABC "
    sSQL = sSQL & "     FROM tableC " & vbCrLf
    Set objRst = OraDatabase.DbCreateDynaset(sSQL, 0&)
    
    count = objRst.RecordCount
    
    '***オラクル切断***
    Call Close_Session
    
End Sub

この際に、ループ内でエラーが発生したら、そのときのデータのINSERTはロールバックするが、
処理を続行し次のデータの処理へ進むためには
「On Error GoTo err_C」

「err_C:
'    OraSession.rollback
     errmsg = "データの登録に失敗しました。<< エラー内容 >>" & Err.Description
     fileNo = FreeFile                         'ファイル番号の取得
     Open "ERRLOG.TXT" For Append As #fileNo   'ファイルを追加モードで開く
     Print #fileNo, errmsg & vbCrLf            'ファイルへ書き込む
     Close #fileNo」

をどこに記述したらよいでしょうか?
それ以前にOn ERROR Go Toで私がやりたいことを実行するのは可能でしょうか?

よろしくお願い致します。

[ツリー表示へ]
タイトルRe: エラーになっても処理を続行させたい
記事No12829
投稿日: 2008/07/26(Sat) 15:06
投稿者魔界の仮面弁士
> 処理を続行し次のデータの処理へ進むためには
> 「On Error GoTo err_C」
そのプロシージャ内で、「エラーが発生する可能性がある場所」よりも前であれば
どこでも構いません。

Visual Basic のエラー処理については、VB6 付属の MSDN ライブラリに
チュートリアルとして細かく解説されていますので、コーディング作業の前に
一度目を通しておいてください。


> 「err_C:
> '    OraSession.rollback
>      errmsg = "データの登録に失敗しました。<< エラー内容 >>" & Err.Description
>      fileNo = FreeFile                         'ファイル番号の取得
>      Open "ERRLOG.TXT" For Append As #fileNo   'ファイルを追加モードで開く
>      Print #fileNo, errmsg & vbCrLf            'ファイルへ書き込む
>      Close #fileNo」
プロシージャ内であれば、どこに記述しても構いません。

ただし、この処理がエラー処理以外の目的で実行されることが無いようにするため、
 (1) Exit Sub (End Sub では無い)よりも後の行に書く。
 (2) If ステートメント等で、Err.Number によるエラーコード判定を併用する。
 (3) GoTo ステートメントなどを併用して、通常処理時にはエラー処理ブロックを
  通過させないようにしておく。
などといった対処を施す必要があります。(一般的には 案1 が採用されます)


> それ以前にOn ERROR Go Toで私がやりたいことを実行するのは可能でしょうか?
On Error Resume Next でも良い気がしますが、On Error GoTo を採用するのであれば、
エラー発生後に「エラー発生行の次の行から処理を続行する」ために、
err_C ラベル以降のエラー処理ルーチンの最後に、Resume Next ステートメントを
記述しておく必要があります。

[ツリー表示へ]
タイトルRe^2: エラーになっても処理を続行させたい
記事No12831
投稿日: 2008/07/27(Sun) 00:08
投稿者eco
回答ありがとうございます。

Visual Basic のエラー処理をもう一度確認します。

> > 「err_C:
> > '    OraSession.rollback
> >      errmsg = "データの登録に失敗しました。<< エラー内容 >>" & Err.Description
> >      fileNo = FreeFile                         'ファイル番号の取得
> >      Open "ERRLOG.TXT" For Append As #fileNo   'ファイルを追加モードで開く
> >      Print #fileNo, errmsg & vbCrLf            'ファイルへ書き込む
> >      Close #fileNo」
> プロシージャ内であれば、どこに記述しても構いません。
>
> ただし、この処理がエラー処理以外の目的で実行されることが無いようにするため、
>  (1) Exit Sub (End Sub では無い)よりも後の行に書く。
>  (2) If ステートメント等で、Err.Number によるエラーコード判定を併用する。
>  (3) GoTo ステートメントなどを併用して、通常処理時にはエラー処理ブロックを
>   通過させないようにしておく。
> などといった対処を施す必要があります。(一般的には 案1 が採用されます)

今回Loopの前に記述する必要があるように思えるのですが、
そうなるとExit Subは記述できないですよね。
特にOn ERROR Go Toにこだわる必要がなければ、On Error Resume Nextで
If分岐でエラーコード判定を行ったほうがすっきり書けますかね・・・?

[ツリー表示へ]
タイトルRe^3: エラーになっても処理を続行させたい
記事No12833
投稿日: 2008/07/27(Sun) 13:04
投稿者魔界の仮面弁士
> Visual Basic のエラー処理をもう一度確認します。
具体的には、MSDN ヘルプファイルの下記の項目です。

[Visual Basic ドキュメント]
├[Visual Basic の使用方法]
│└[プログラミング ガイド]
│ └[Visual Basic を使ってできること]
│  └[コードのデバッグおよびエラー処理]☆
│   ├[エラーの処理方法]★
│   ├[エラー処理ルーチンの構成]★
│   ├[エラー処理ルーチンの階層]★
│   ├[エラーの生成]★
│   ├[インライン エラー処理]★
│   ├[エラーの集中処理]★
│   └[エラー処理の無効化]★
└[リファレンス]
 └[ランゲージ リファレンス]
  └[ステートメント]
   ├[I-P]
   │└[On Error ステートメント]★
   └[R-Z]
    └[Resume ステートメント]★


> 今回Loopの前に記述する必要があるように思えるのですが、
事前に記述するのは、エラートラップの指示(On Error GoTo 〜)だけです。
先にも書きましたように、エラー処理本体そのものは、
プロシージャ内であれば、どこに記述しても構いません。

> If分岐でエラーコード判定を行ったほうがすっきり書けますかね・・・?
エラー処理が発生する可能性がある部分を、別のプロシージャにしておくことで
処理手順を整理できる可能性があります。


で。今回のコードの場合、下記のような点についても見直しておくべきかと。

・そもそも、ループ中にどのようなエラーが発生することが想定されているのか。
 (エラーを事前に想定せず、無計画にトラップするのは避けるべきです)

・ループのたびに、バインド変数の削除と登録をやり直す必要は無いのでは、
 ループ前に登録、ループ中はValue の書き換えのみ、ループ後に削除、とか。

・各 SQL の内容は固定的なので、ループ中で再生成したり、一つの sSQL 変数を
 使いまわしてたりするのではなく、すべてループ前に用意しておいた方が良いのでは。

・objRst は編集しないのだから、DbCreateDynaset を 0& で呼ぶ必要は無いのでは。
 たとえば、12&(ORADYN_NOCACHE Or ORADYN_READONLY) とか。

・この処理をループ処理せずに実現できる方法は無いのか?
 たとえば、MERGE 命令などを用いて、より効率のよい記述をできないか。

・最後の RecordCount 処理を、SELECT COUNT(*) に修正すべき。
 今のコードだと、ABC 列の値を読み捨てる結果になるので、効率が悪いです。

[ツリー表示へ]
タイトルRe^4: エラーになっても処理を続行させたい
記事No12844
投稿日: 2008/07/28(Mon) 21:54
投稿者eco
ありがとうございます。
今回は On Error Resume Nextで、
INSERT文のあとにエラーの条件分岐でエラー処理を行うことにしました。
ご指摘ありがとうございます。今日見直してバインド変数と件数取得のところを変更しました。

> ・各 SQL の内容は固定的なので、ループ中で再生成したり、一つの sSQL 変数を
>  使いまわしてたりするのではなく、すべてループ前に用意しておいた方が良いのでは。
これはObjRst.Refreshっていうことですかね・・・?ちょっとまだ調べている段階です。

> ・objRst は編集しないのだから、DbCreateDynaset を 0& で呼ぶ必要は無いのでは。
>  たとえば、12&(ORADYN_NOCACHE Or ORADYN_READONLY) とか
> ・この処理をループ処理せずに実現できる方法は無いのか?
>  たとえば、MERGE 命令などを用いて、より効率のよい記述をできないか。
この二点についてもまだ調べているので、解決していませんが、
エラー処理の点自分なりに解決できたんじゃないかと思ったので報告致します。

DbCreateDynaset を 0& で呼ぶっていうのも1年間この方法だけでやっていたので
ちゃんと勉強したいと思います。


ありがとうございました。

[ツリー表示へ]