プロが教える店舗&オフィスのセキュリティ対策術

タブ区切りのtsvファイルの1項目目に並んでいるデータをDBのプライマリーキーとみなして、DB上に既にあればupdate、なければinsertします。
下のPGは、DBに30万件のデータが入った状態で実行すると、遅すぎて使えません。もっと速くすることはできませんでしょうか。

Public Const OraSQL_01 = "INSERT INTO CUSTOMER (COMPANY_CODE, TEST1) Values (:データ0, :データ1)"

Public Const OraSQL_02 = "UPDATE CUSTOMER SET COMPANY_CODE = :データ0, TEST1 = :データ1 WHERE COMPANY_CODE = :データ0"

wkFile1 = "c:\test\test.csv"
Open wkFile1 For Input As #1

OraSession.BeginTrans
Set rs = OraDatabase.CreateDynaset("SELECT COMPANY_CODE FROM CUSTOMER", ORADYN_DEFAULT)
OraDatabase.Parameters.Add "データ0", 0, ORAPARM_INPUT
OraDatabase.Parameters("データ0").ServerType = ORATYPE_NUMBER
OraDatabase.Parameters.Add "データ1", 0, ORAPARM_INPUT
OraDatabase.Parameters("データ1").ServerType = ORATYPE_VARCHAR2

Do Until EOF(1)
Line Input #1, Text
sec = Split(Text, vbTab)

OraDatabase.Parameters("データ0").Value = sec(0)
OraDatabase.Parameters("データ1").Value = sec(1)

Dim flg As Boolean
Do Until rs.EOF
flg = False
If rs("COMPANY_CODE") = sec(0) Then
OraDatabase.ExecuteSQL OraSQL_02
flg = True
Exit Do
Else
rs.MoveNext
End If
Loop

If flg = False Then
OraDatabase.ExecuteSQL OraSQL_01
End If
rs.MoveFirst
Loop
OraSession.CommitTrans

A 回答 (4件)

 ざっと眺めただけだが確かに遅すぎて使えそうにないな。



アプローチ1.tsvから1行読み込んだら、1列目(顧客コード)をキーにselectして引っかかればupdate、引っかからなければinsertを実行するように変更する。
 これはあれなのかな? ひょっとしたらtsvに同じ顧客コードが2行以上あった時に、毎回selectするとエラーが発生せずに1回目に出てきたの餡餅商事はinsert→2回目以降に出てきた餡餅商事はupdateでエラーが発生せずに終わってしまうからダメなのかな? それならこのアプローチを取らなかった理由は分かる。

アプローチ2.顧客コード一覧をダイナセットで取る時に顧客コードを昇順でソートし、バイナリサーチを使うように変更する。
 これは説明の必要もないだろう。シーケンシャルサーチはありえんだろう。30万行やし。

この回答への補足

anmochiさんご回答有難うございます。
恐縮ですが、アプローチ1をとる場合の書き方がわかりません。
1列目をキーにSELECTしてダイナセットで取るには

Set rs = OraDatabase.CreateDynaset("SELECT COMPANY_CODE FROM CUSTOMER WHERE COMPANY_CODE = :データ0", ORADYN_DEFAULT)
でよいかと思いますが、ひっかかっる、ひっかからないのコードはどのように記述すれば宜しいのでしょうか、わかれば教えて頂けませんでしょうか。

宜しくお願いします。

補足日時:2004/09/21 13:40
    • good
    • 0
この回答へのお礼

コードの記述方法がわかりました。
Set rs = OraDatabase.CreateDynaset("SELECT COMPANY_CODE FROM CUSTOMER WHERE COMPANY_CODE = :データ0", ORADYN_DEFAULT)

If rs("COMPANY_CODE") = sec2(0) Then
OraDatabase.ExecuteSQL OraSQL_02
Else
OraDatabase.ExecuteSQL OraSQL_01
End If

でできました。
有難うございました。

お礼日時:2004/09/21 20:53

こんな手も。



1.空のテンポラリの表を作成。主キーもつけておく。

2.テキストファイルの内容をテンポラリ表にSQL*Loaderでロード

3.更新対象のデータをCUSTOMERから削除
delete from CUSTOMER where COMPANY_CODE in (select COMPANY_CODE from テンポラリ表);

4.テンポラリ表の内容をCUSTOMERに追加
insert into CUSTOMER select * from テンポラリ表;

5.テンポラリ表の削除。


#CUSTOMERテーブルの行数だけではなく、テキストファイルの行数も多ければ、下手にロジック組むよりこの方が高速です。
    • good
    • 0

Oracle のバージョンはいくつでしょうか?


9i 以降だったら MERGE が使えますけど。
    • good
    • 0

selectというか、Dynaset不要。

insertして一意制約違反だったらupdateすればいいだけ。
updateの際は、主キーの項目はsetに含めない。
    • good
    • 1

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