Access VBAでクエリを実行する方法をお探しですね。

広告

AccessのRunSQLとCurrentDb.Executeの違いと使い分け──安全にデータを更新するための実践ガイド

Accessでフォームのボタンから一括更新したり、CSV取り込み後に不要なデータを削除したりするとき、VBAからアクションクエリやSQL文を実行する場面がよくあります。

そんなとき使われるのが「DoCmd.RunSQL」と「CurrentDb.Execute」という2つの方法です。

どちらも「SQLを実行できる」という点では同じなので、違いを意識せずに使っている人も多いかもしれません。

でも実は、この2つにはちゃんと違いがあって、使い分けを知っておかないと思わぬトラブルにつながることもあります。

この記事では、Access VBAでアクションクエリやSQL文を安全に実行するために、RunSQLとExecuteの違い、エラー処理の書き方、トランザクションの使い方、そして実務で気をつけるべきポイントを、できるだけわかりやすく整理して解説します。

1. Access VBAでアクションクエリやSQL文を実行する基本

まず「アクションクエリ」って何?という話からです。

Accessでいうアクションクエリとは、データを表示するだけのSELECTクエリとは違って、**テーブルの中身を実際に変更するクエリ**のことを指します。

具体的には、次のようなものです。

– **INSERT INTO**:データを追加する
– **UPDATE**:データを更新する
– **DELETE**:データを削除する
– **SELECT INTO**:新しいテーブルを作成する

これらをVBAから実行できるようにすると、フォームのボタンをクリックしたときの処理や、毎日の定型作業、取り込んだデータの整形、複数のクエリを連続で実行する処理などを自動化できます。

便利ですよね。

ただし、アクションクエリは**実行した瞬間にデータが書き換わる**ので、SELECTクエリよりも慎重に扱う必要があります。

間違えて全件削除しちゃった…なんてことになったら大変です。

Access VBAでSQL文を実行する方法はいくつかありますが、実務でよく比較されるのが**DoCmd.RunSQL**と**CurrentDb.Execute**です。

– **DoCmd.RunSQL**は、Accessの画面操作に近い感覚でSQLを実行できる方法です。

コードが短くて済むので、初心者にも使いやすいのが特徴です。

– **CurrentDb.Execute**は、DAOのDatabaseオブジェクトを使ってSQLを実行する方法です。

確認メッセージが出ないので自動処理に向いていて、エラー処理やトランザクション制御と組み合わせやすいのが強みです。

「とりあえず動けばいい」ではなく、**処理が失敗したときにちゃんと検知できるか**、**後から見直しやすいか**まで考えることが大事です。

たとえば、RunSQLを使うとこんなふうに書けます。

SQL文は文字列として書くので、テーブル名やフィールド名、文字列・日付の囲み方を間違えるとエラーになったり、意図しない更新が起きたりします。

Access SQLでは、文字列はシングルクォーテーション(`’`)、日付はシャープ記号(`#`)で囲むのが基本です。

“`vba
DoCmd.RunSQL “UPDATE T_商品 SET 単価 = 単価 * 1.1 WHERE 分類 = ‘文具’;”
“`

同じ処理をCurrentDb.Executeで書くと、こうなります。

第二引数に`dbFailOnError`を指定することで、主キーの重複や制約違反などのエラーをVBA側でキャッチしやすくなります。

業務システムでは、**エラーが起きたのに処理が進んでしまう**ことが一番危険なので、Executeを使うときは`dbFailOnError`を付けるクセをつけておくと安全です。

“`vba
CurrentDb.Execute “UPDATE T_商品 SET 単価 = 単価 * 1.1 WHERE 分類 = ‘文具’;”, dbFailOnError
“`

2. DoCmd.RunSQLの特徴と使いどころ

DoCmd.RunSQLの一番の特徴は、**コードが短くて、Accessのマクロや画面操作に近い感覚で使える**ことです。

保存済みクエリを開く`DoCmd.OpenQuery`と同じように、Accessの標準機能として理解しやすいので、小規模な更新処理や、管理者だけが使う簡易ツールでは十分に役立ちます。

ただし、デフォルトでは「○件のレコードを更新します」といった**確認メッセージが表示される**ことがあります。

自動処理やボタン処理では、この確認が邪魔になる場合がありますよね。

そのため、RunSQLを使うコードでは`DoCmd.SetWarnings False`で警告を消す例がよく見られます。

でも、**SetWarnings Falseを使うときは注意が必要**です。

処理の途中でエラーが起きて、`SetWarnings True`に戻らないまま停止すると、その後にAccess上でクエリを手動実行したときにも警告が出ない状態が残ることがあります。

特に削除クエリや更新クエリでは、確認なしでデータが変わってしまうリスクがあるので、**エラーが起きても必ず警告設定を元に戻す**構造にしておくべきです。

RunSQL自体が悪いわけではありませんが、「警告を消して実行する」書き方を安易にコピペすると、運用上の事故につながりかねません。

安全性を考えるなら、RunSQLを使う場合でも次のように**エラー処理を入れて、最後にSetWarnings Trueへ戻す**形にしましょう。

“`vba
On Error GoTo ErrHandler

DoCmd.SetWarnings False
DoCmd.RunSQL “DELETE FROM T_取込一時 WHERE 取込日 < #2024-01-01#;”
DoCmd.SetWarnings True

Exit Sub

ErrHandler:
DoCmd.SetWarnings True
MsgBox “SQLの実行に失敗しました: ” & Err.Description
“`

実務では、処理の前に**対象件数をSELECT COUNTで確認する**、**実行前にバックアップを取る**、**更新条件をフォームの入力値から組み立てる場合はNullや空文字をチェックする**といった事前確認も欠かせません。

特に**WHERE句の付け忘れ**は、全件更新や全件削除の原因になるので要注意です。

短いSQLほど油断しないようにしましょう。

RunSQLが向いているのは、こんな場面です。

– 影響範囲が小さく、処理内容が明確
– ユーザーに確認メッセージを見せても問題ない
– 開発中の一時的なデータ整理
– 管理者専用フォームの単発更新
– 学習用のサンプル処理

逆に、**複数の更新を連続して行う処理**、**大量データを扱う処理**、**失敗時にロールバックしたい処理**では、RunSQLよりもCurrentDb.Executeを選ぶほうが適しています。

3. CurrentDb.Executeの特徴と実務で推奨される理由

CurrentDb.Executeは、**DAOのDatabaseオブジェクトに対してSQLを実行する**方法です。

RunSQLと違って**Accessの確認メッセージは表示されない**ので、自動処理やバッチ処理、フォームのボタンから複数のアクションクエリを実行する処理に向いています。

さらに、`dbFailOnError`を指定すれば、制約違反やロックなどによる失敗をエラーとして扱いやすくなります。

業務データを扱うAccessでは、「成功したつもりで次の処理へ進む」ことを防ぐためにも、**Executeとエラー処理を組み合わせる設計**が重要です。

実務では、`CurrentDb`を何度も直接呼び出すより、**Database型の変数に代入して使う**書き方がよく使われます。

`CurrentDb`は現在開いているデータベースを返すメソッドなので、コード中に何度も書くよりも、最初に`Set db = CurrentDb`としておくほうが処理の見通しがよくなります。

また、`db.RecordsAffected`を参照すると、**直前に実行したアクションクエリで影響を受けたレコード数**を確認できます。

これは「更新対象が0件だったら警告を出す」「想定件数より多ければ処理を止める」といった業務チェックに役立ちます。

“`vba
Dim db As DAO.Database
Set db = CurrentDb

db.Execute “UPDATE T_在庫 SET 数量 = 数量 – 1 WHERE 商品ID = 1001;”, dbFailOnError

If db.RecordsAffected = 0 Then
MsgBox “更新対象の在庫データが見つかりませんでした。


End If
“`

CurrentDb.Executeの大きな利点は、**トランザクション制御と組み合わせやすい**点です。

トランザクションとは、**複数の更新処理をひとまとまりとして扱い、すべて成功した場合だけ確定し、途中で失敗した場合は元に戻す**仕組みです。

たとえば、売上テーブルに追加して、在庫テーブルを更新して、履歴テーブルにも書き込む処理で、途中の在庫更新だけ失敗するとデータの不整合が起きますよね。

このような処理では、`BeginTrans`、`CommitTrans`、`Rollback`を使って一貫性を守る必要があります。

“`vba
On Error GoTo ErrHandler

Dim db As DAO.Database
Set db = CurrentDb

DBEngine.Workspaces(0).BeginTrans

db.Execute “INSERT INTO T_売上 (商品ID, 数量) VALUES (1001, 1);”, dbFailOnError
db.Execute “UPDATE T_在庫 SET 数量 = 数量 – 1 WHERE 商品ID = 1001;”, dbFailOnError

DBEngine.Workspaces(0).CommitTrans
MsgBox “登録が完了しました。


Exit Sub

ErrHandler:
DBEngine.Workspaces(0).Rollback
MsgBox “処理に失敗したため、変更を取り消しました: ” & Err.Description
“`

ただし、CurrentDb.Executeにも注意点があります。

**パラメータ付きの保存済みクエリを実行したい場合**、単純なCurrentDb.Executeではパラメータを渡せないことがあります。

その場合は**QueryDefオブジェクト**を使い、Parametersコレクションに値を設定してからExecuteする方法が適しています。

フォームの入力値をSQL文字列に連結するだけの実装は、引用符のミスや日付形式の揺れ、シングルクォーテーションを含む文字列でのエラーを招くため、複雑な条件や再利用する処理ではQueryDefの利用も検討するとよいです。

4. RunSQLとCurrentDb.Executeの使い分けと安全な実装手順

RunSQLとCurrentDb.Executeの違いは、「どちらがSQLを実行できるか」ではなく、**「どのように安全に実行結果を管理できるか」**にあります。

– **RunSQL**は手軽でわかりやすい反面、警告メッセージの制御やエラー処理を雑に書くと危険です。

– **CurrentDb.Execute**は少しコード量が増えますが、`dbFailOnError`、`RecordsAffected`、トランザクションと組み合わせることで、業務処理としての信頼性を高められます。

長く使うAccessシステムや、担当者が変わっても保守する必要があるデータベースでは、**Executeを基本に考えるほうが無難**です。

判断基準を整理すると、こんな感じです。

– **RunSQL**:単発・小規模・確認メッセージが許容される処理に向く
– **CurrentDb.Execute**:大量更新・自動処理・エラー検知が必要な処理に向く

保存済みクエリを使うか、VBA内にSQL文を直接書くかも重要な判断です。

保存済みクエリはAccessの画面で内容を確認しやすく、再利用しやすいメリットがあります。

一方、VBA内にSQLを直接書くと、条件分岐やフォーム入力に応じた動的なSQLを作りやすく、処理の流れをコード上で追いやすくなります。

実務で迷ったときは、次の基準で選ぶと整理しやすくなります。

– **簡単な単発処理や学習用途**なら、DoCmd.RunSQLでもOK
– **業務データを更新する本番処理**なら、CurrentDb.ExecuteとdbFailOnErrorを基本にする
– **複数の更新をまとめて行う**なら、トランザクションを使う
– **パラメータ付き保存クエリを使う**なら、QueryDef.Executeを検討する
– **実行前にはSELECTやCOUNTで対象件数を確認**する

SQL文を組み立てる際は、**データ型**にも注意が必要です。

– 文字列はシングルクォーテーション(`’`)で囲む
– 日付はシャープ記号(`#`)で囲む
– Null判定は「`= Null`」ではなく「`IS NULL`」を使う

こうしたAccess SQLの基本を守らないと、エラーにならなくても結果が0件になることがあります。

特に**日付条件**では、表示上は同じ日付に見えても時刻部分が含まれているため、期待したレコードが更新されないことがあります。

アクションクエリを実行する前に、**同じWHERE句でSELECT文を作り、対象レコードを確認する習慣**を持つと事故を減らせます。

まとめ

Access VBAでアクションクエリやSQL文を実行する際の基本方針は、**「小さな処理はわかりやすく、大事な処理は安全に」**です。

– **RunSQL**は手早く処理を書ける便利な方法ですが、警告抑制やエラー検知に弱点があります。

– **CurrentDb.Execute**は実務向けの堅実な方法で、`dbFailOnError`、`RecordsAffected`、トランザクションを組み合わせることで、更新結果を確認しながら処理できます。

Accessは手軽に作れる反面、**設計の差が後から大きく出る**ツールです。

データを変更する処理ほど、「失敗したときにどう戻すか」「想定外の件数をどう検知するか」まで含めて実装することが大切です。

この記事が、安全で保守しやすいAccessシステムを作るヒントになれば幸いです。

広告