- 締切済み
CSVを取込むストアドプロシージャで、1件目が登録されない現象が起きています
いつもお世話になっております 古い環境なので大変恐縮ですが、行き詰ってしまったので、 ご教示いただきたいと思います。 環境: WinXP sp2 SQLServer8.0 VB6.0 sp4 VBでCSVのデータ1行について、ストアドプロシージャにて3つのテーブルに格納しようとしています。 トランザクションの管理はVB側で行っています。 1行ごとにCommitを行えば、全行格納されるのですが、 2行以上ごとにCommitを行うと、最初の1行のみが格納されないという現象がおきています。 6800行存在する同じCSVファイルについて、1行ごとにCommitを行った場合は、6800件登録されるのに 処理の最後でCommitをきった場合、6799行しか登録されません。 1行ごとにCommitをきった場合に6800行登録されるので、キー重複は考えられません。 いろいろ試してみたことを下記に書きます 結果はこのような感じです。 CASE1・・・全件登録できます CASE2・・・2件目で重複エラーが発生します CASE3・・・全件 - 1件が登録できます CASE4・・・全件登録できます CASE5・・・全件登録できます CASE2, CASE3 で全件登録できない理由をご教示いただきたく思います。 よろしくお願いいたします。 CASE1(VBでINSERT文を記述) localConnection.beginTrans localConnection.execute "DELETE FROM TABLE_A" localConnection.execute "DELETE FROM TABLE_B" localConnection.execute "DELETE FROM TABLE_C" FOR i = 1 to 6800 localConnection.execute "INSERT INTO TABLE_A (COL_A1, COL_A2) VALUES ('" & VAL_A1(i) & "','" & VAL_A2(i) & "')" localConnection.execute "INSERT INTO TABLE_B (COL_B1, COL_B2) VALUES ('" & VAL_A1(i) & "','" & VAL_B2(i) & "')" localConnection.execute "INSERT INTO TABLE_C (COL_C1, COL_C2) VALUES ('" & VAL_A1(i) & "','" & VAL_C2(i) & "')" NEXT localConnection.commitTrans CASE2(ストアドプロシージャ) localConnection.beginTrans localConnection.execute "DELETE FROM TABLE_A" localConnection.execute "DELETE FROM TABLE_B" localConnection.execute "DELETE FROM TABLE_C" ' -- ストアドプロシージャのパラメータ作成 FOR i = 1 to 6800 localConnection.execute NEXT localConnection.commitTrans CASE3(ストアドプロシージャ) localConnection.beginTrans localConnection.execute "DELETE FROM TABLE_A" localConnection.execute "DELETE FROM TABLE_B" localConnection.execute "DELETE FROM TABLE_C" localConnection.commitTrans ' -- ストアドプロシージャのパラメータ作成 localConnection.beginTrans FOR i = 1 to 6800 localConnection.execute NEXT localConnection.commitTrans CASE4(ストアドプロシージャ) localConnection.beginTrans localConnection.execute "DELETE FROM TABLE_A" localConnection.execute "DELETE FROM TABLE_B" localConnection.execute "DELETE FROM TABLE_C" localConnection.commitTrans ' -- ストアドプロシージャのパラメータ作成 localConnection.beginTrans FOR i = 1 to 6800 localConnection.execute localConnection.commitTrans localConnection.beginTrans NEXT localConnection.commitTrans CASE5(ストアドプロシージャ) localConnection.beginTrans localConnection.execute "DELETE FROM TABLE_A" localConnection.execute "DELETE FROM TABLE_B" localConnection.execute "DELETE FROM TABLE_C" localConnection.commitTrans ' -- ストアドプロシージャのパラメータ作成 localConnection.beginTrans FOR i = 1 to 6800 localConnection.execute if i = 1 then localConnection.commitTrans localConnection.beginTrans end if NEXT localConnection.commitTrans
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- khazad-lefty
- ベストアンサー率44% (296/668)
(今確認中かもですが) 前回の解答でも言いましたが、Case2で追うといいと思います。 理由は単純に「2回目のループで」「エラーが発生する」からです。 たとえばこんな感じのコード(これでは動かないかもですがそのあたりは適当に修正してください)で、 for i=0 to 6800 pCmd.Parameters("@i_ParamA1").Value = strVALA1(i) pCmd.Parameters("@i_ParamA2").Value = strVALA2(i) pCmd.Parameters("@i_ParamB2").Value = strVALB2(i) pCmd.Parameters("@i_ParamC2").Value = strVALC2(i) 'debug(S) Dim RS as recordset set RS = ("Select * from tableA" の結果) '******ブレークポイント********** 'debug(E) localConnection.execute next で、上記ブレークポイントで2件目のInsert直前で 1. レコードセットRSの状態(件数が1件なのか、キー列の値は?) 2.(strVALA1(i)ではなく)pCmd.Parameters("@i_ParamA1").Valueの値 を確認した場合、「素直に考えたら」キーが重複するような状態になっているはずです。 どういう状態になっているでしょうか? あと、エラーが発生する場合、そのメッセージはどういう形になるのでしょうか(極力正確に) #それでもだめなら中間テーブル経由するとか代替案を考えるしかないんじゃないかと。
- khazad-lefty
- ベストアンサー率44% (296/668)
ストアドのみで発生するということは、それに関係する部分に原因があると考えるのが自然だと思います。 たとえば、パラメータオブジェクトの値が更新されてないとか。 そのあたり記述されてないので良くわからないですが。 まず、Case2が「2件目で」重複エラーになるのが取っ掛かりになるんじゃないかと。重複しているのはどの列、どの値なのか(何件目のデータが重複しているのか)などがヒントになると重います。 デバッグ実行で、実行するタイミングでのパラメータがどうなっているかを確認すると答えになるんじゃないかと思います。 あと、ストアド実行直後に同じコネクションでレコードセットを取得して、その内容を確認すればその時点のテーブルがどういう状況下という確認はかのうですよね?そのあたり確認すれば原因がわかるのではないかと。
補足
質問が中途半端で申し訳ありません。 まず、パラメータ設定は下記のように行っています pCmd.CommandText = "(ストアド名)" pCmd.CommandType = adCmdStoredProc Dim prm As New ADODB.Parameter Set prm = New ADODB.Parameter Set prm = pCmd.CreateParameter("ReturnVal", adInteger, adParamReturnValue) pCmd.Parameters.Append prm Set prm = pCmd.CreateParameter("@i_ParamA1", adChar, adParamInput, 5) pCmd.Parameters.Append prm Set prm = pCmd.CreateParameter("@i_ParamA2" adVarChar, adParamInput, 50) pCmd.Parameters.Append prm Set prm = pCmd.CreateParameter("@i_ParamB2", adVarChar, adParamInput, 50) pCmd.Parameters.Append prm Set prm = pCmd.CreateParameter("@i_ParamC2", adChar, adParamInput, 2) pCmd.Parameters.Append prm 次に、Executeの直前で、下記のように設定しています pCmd.Parameters("@i_ParamA1").Value = strVALA1(i) pCmd.Parameters("@i_ParamA2").Value = strVALA2(i) pCmd.Parameters("@i_ParamB2").Value = strVALB2(i) pCmd.Parameters("@i_ParamC2").Value = strVALC2(i) Table_A,Table_B,Table_CのPrimaryKeyはすべて、strVALA1(i)が格納されるべきCOL_A1で、 6800件について、全て重複なく、NULLでもないことを確認しています。 そのほかのA2,B2,C2についても、重複している点はみあたりませんでした。 ストアド実行直後に、イミディエイトウィンドウからコミットをかけ、 SQLServerのテーブルを見てみましたが、1件1件だと、きちんと登録されているようでした。
補足
何度も大変ご丁寧な解説ありがとうございます。 昨日、この作業を含め、いろいろ試してみました。 やはり、重複が気になったので、FOR文のカウントをそのままキーに 入れてみたり、トランザクションの分離レベルを変更したりもしました。 ご教示いただいた内容について Executeの前後でレコードセットを調べてみました。 キー項目には、For文のカウントをCstrしてそのままキーに入れる(=重複はありえない)ようにしています。 1件目の直前ではゼロ件 / 直後で1件(1件目が正常に登録されている)、 2件目の直前では1件(1件目が正常に登録されている) になっており、2件目のExecuteで、VB側のエラーオブジェクトが重複エラーを検出しました。 VB側エラーオブジェクト err.Number -2147217873 err.Description PRIMARY KEY 違反、制約 'PK_TABLE_A': オブジェクト 'TABLE_A' には重複したキーは挿入できません。 もちろん、ストアドプロシージャ側でもエラーログを出力しており、 エラーがあった場合にはクライアントに返す処理も行っています ----------------------------------------------- INSERT INTO TABLE_A (...) VALUES (...) SELECT @Error = @@Error,@ROWCOUNT = @@ROWCOUNT if @Error != 0 BEGIN RaisError('<%s>(%s[%s]) TABLE_Aの挿入時にエラーが発生しました。 Error=%d',10,1,@PROCEDURE_NAME,@HostName,@ApName,@Error) WITH LOG,NOWAIT SET @o_ErrMsg = '<' + @PROCEDURE_NAME + '>TABLE_Aの挿入時にエラーが発生しました。 Error=' + @Error GOTO ErrHandle END ErrHandle: /* エラー発生 戻り値は1 */ RETURN 1 ----------------------------------------------- しかし、SQLServerのエラーログには記述されているものの、 そこからクライアントに1が返ってきているのではなく VB側のエラーオブジェクトでした。 また、この時点で気になったのが、RS をCloseするとVB側でエラーが検出され、 RSをCloseしないと、2件目以降が正常に登録されていくということを確認しています。 トランザクションの分離レベルも、READ UNCOMMITTEDにしてみましたが、 やはり、重複エラーを返すようです。 まだ決定的ではありませんが、今のところ、下記の推測がたちました。 ・beginTrans → VB側でDELETE → ストアドでINSERT → commitTrans の流れで、 DELETEが確実に行われていないのではないだろうか? これから、他のテーブルでも同じような現象が起きるかどうかを調べてみます。 ありがとうございました。