Access フロントエンド + SQL Server バックエンド環境において,SQL Server 2022 へ移行後,「データの競合」エラーが頻発する現象が発生した。
発生した現象
Access フォームやリンクテーブル編集時に,以下のエラーが頻発。
このレコードは,他のユーザーによって変更されています。
発生条件はかなり単純で,
- サブフォームへフォーカス移動
- 単純な UPDATE
- テーブル直接編集
でも発生した。
環境
- Access フロントエンド
- SQL Server 2022
- ODBC Driver 18 for SQL Server
- SQL Server リンクテーブル
- 主キーあり
- trigger なし
テーブルには DEFAULT(GETDATE()) が設定されていた。
当初疑ったもの
まず以下を疑った。
- サブフォーム自動保存
- DEFAULT(GETDATE())
- datetime 精度
- ODBC Driver 18
- ダイナセット(矛盾を許す)
- trigger
しかし,単純なテーブル編集でも発生したため,「更新対象行の識別」に問題がある可能性が高くなった。
原因
Access は SQL Server 更新時に,
「自分が開いた行」と「現在のDB上の行」
を比較して楽観ロックを行っている。
しかし rowversion 列が無い場合,
- datetime
- NULL
- 自動更新列
- DEFAULT値
などを含めて比較している可能性があり,ODBC Driver 18 環境では競合判定が厳格化しているようだった。
結果として,
実際には他ユーザー更新ではないのに「競合」と判定
されていた。
解決方法
SQL Server テーブルへ rowversion 列を追加。
ALTER TABLE dbo.T_HOGE
ADD タイムスタンプ rowversion NOT NULL;
追加後,競合エラーは解消。
補足
SSMS 上では列型が timestamp と表示されるが問題ない。
SQL Server では:
timestamp= 旧名称rowversion= 推奨名称
という関係であり,内部的には同じ型。
なお,これは日時ではなく,自動更新される binary(8) のバージョン番号である。
実務上の所感
Access + SQL Server 環境では,特に以下の構成で rowversion の重要性が高いと感じた。
- SQL Server 2019 / 2022
- ODBC Driver 17 / 18
- Access 旧資産
- DEFAULT値あり
- 自動保存あり
Access 側に問題が見えていても,実際には SQL Server 側の rowversion 不在が原因となっているケースがある。

コメント