行が存在する場合は更新され、存在しない場合は挿入されるように、MS-Access 2000 用の SQL クエリを作成する必要があります。(これは「アップサート」と呼ばれると思います)
すなわち
行が存在する場合...
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
存在しない場合...
INSERT INTO Table1 VALUES (...)
これは 1 つのクエリで実行できますか?
クエリを使用して Access で upsert をシミュレートできます。UPDATE
LEFT JOIN
update b
left join a on b.id=a.id
set a.f1=b.f1
, a.f2=b.f2
, a.f3=b.f3
Column1に一意のインデックスがあると仮定すると、式を使用して、 Column1 = 'SomeValue' のDCount
行が 0 行か 1 行かを判断できます。次に、またはそのカウントに基づいて。INSERT
UPDATE
If DCount("*", "Table1", "Column1 = 'SomeValue'") = 0 Then
Debug.Print "do INSERT"
Else
Debug.Print "do UPDATE"
End If
私は、最初に を試みINSERT
、3022 キー違反エラーをトラップUPDATE
し、エラーに応答して を実行するよりも、このアプローチを好みます。しかし、私のアプローチから大きな利益を得ることはできません。テーブルに autonumber フィールドが含まれている場合、failed を回避するINSERT
と、次の autonumber 値を不必要に消費するのを防ぐことができます。INSERT
また、必要のない文字列を作成することを避けることもできます。Access Cookbookによると、VBA では文字列の連結はかなりコストのかかる操作なので、実際に必要でない限り、文字列の作成を避ける機会を探しています。このアプローチにより、不要な のロックの作成も回避されINSERT
ます。
ただし、これらの理由のいずれも、あなたにとって非常に説得力のあるものではない場合があります。そして、正直なところ、この場合の私の好みは、私にとって「正しいと感じる」ものであると思います。以前のスタック オーバーフローの質問に対する@ David-W-Fenton のコメントに同意します。データベースエンジンに頼って自分自身からあなたを救うのではなく、場所に置いてください。」
通常、最初に挿入ステートメントを実行してから、行が既に存在することを示すエラー 3022 が発生したかどうかを確認します。だから、このようなもの:
On Error Resume Next
CurrentDb.Execute "INSERT INTO Table1 (Fields) VALUES (Data)", dbFailOnError
If Err.Number = 3022 Then
Err.Clear
CurrentDb.Execute "UPDATE Table1 SET (Fields = Values) WHERE Column1 = 'SomeValue'", dbFailOnError
ElseIf Err.Number <> 0 Then
'Handle the error here
Err.Clear
End If
Edit1:
私がここに投稿したことは非常に一般的な解決策であることを述べたいと思いますが、エラーを計画し、プログラムの通常のフローの一部としてそれらを使用することは、一般的に悪い考えと見なされることに注意する必要があります。同じ結果を達成する他の方法。これを指摘してくれた RolandTumble に感謝します。
エラーをキャッチする必要はありません。代わりに、INSERT ステートメントを実行してから確認してください。
CurrentDb.RecordsAffected
状況に応じて、1 または 0 になります。
注: CurrentDB に対して実行することはお勧めできません。データベースをローカル変数にキャプチャすることをお勧めします。
Dim db As DAO.Database
Set db = CurrentDb
db.Execute(INSERT...)
If db.RecordsAffected = 0 Then
db.Execute(UPDATE...)
End If