dポイントプレゼントキャンペーン実施中!

いつもお世話になっております

古い環境なので大変恐縮ですが、行き詰ってしまったので、
ご教示いただきたいと思います。

環境: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

A 回答 (2件)

(今確認中かもですが)


前回の解答でも言いましたが、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の値

を確認した場合、「素直に考えたら」キーが重複するような状態になっているはずです。
どういう状態になっているでしょうか?
あと、エラーが発生する場合、そのメッセージはどういう形になるのでしょうか(極力正確に)

#それでもだめなら中間テーブル経由するとか代替案を考えるしかないんじゃないかと。

この回答への補足

何度も大変ご丁寧な解説ありがとうございます。

昨日、この作業を含め、いろいろ試してみました。
やはり、重複が気になったので、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が確実に行われていないのではないだろうか?

これから、他のテーブルでも同じような現象が起きるかどうかを調べてみます。
ありがとうございました。

補足日時:2008/10/10 08:53
    • good
    • 0

ストアドのみで発生するということは、それに関係する部分に原因があると考えるのが自然だと思います。


たとえば、パラメータオブジェクトの値が更新されてないとか。
そのあたり記述されてないので良くわからないですが。

まず、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件だと、きちんと登録されているようでした。

補足日時:2008/10/09 09:08
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!