PostgreSQL+ReactでAccessを作り直す注意点|検証で詰まった箇所
Northwindのクエリ77本をPostgreSQLへ変換した自社検証で詰まった4箇所を解説。複数値・添付ファイル型の子テーブル分割、Nz・IIf・Formatの移し先、Date()のタイムゾーン、パラメータ・フォーム参照クエリの扱いを整理します。
結論:詰まるのはSQLの書き換えではなく、Accessにしかない仕組みの移し先
AccessをPostgreSQL+Reactの構成で作り直すとき、テーブルと標準的なSQLの移送は素直に進みます。手が掛かるのはその外側、つまりAccessにしかない仕組みをどこへ移すかです。当社はMicrosoft公開のサンプルデータベースNorthwindを題材に、2026年7月の実測で、Accessのクエリ77本をPostgreSQLへ変換してAccess本体の実行結果と突き合わせる検証を行いました(実測の詳細はこちらの記事にまとめています)。この記事では、その検証で実際に手が掛かった4つの箇所を、注意点として共有します。
| 詰まった箇所 | 何が起きるか | 移し先 |
|---|---|---|
| 複数値フィールド・添付ファイル型 | PostgreSQLに直接対応する型がない | 子テーブルへ分割 |
| Nz・IIf・Format | SQL標準にない関数 | COALESCE・CASE式・フロント側 |
| Date()を含むクエリ | 「誰の今日か」が新旧でずれる | タイムゾーンを決めてから移す |
| パラメータ・フォーム参照クエリ | 値が束縛されるまで結果が決まらない | プレースホルダ+アプリ層 |
複数値フィールドと添付ファイル型は、子テーブルへ分割してから移す
Accessには、1つの列に複数の値を持てる複数値フィールドと、レコードにファイルそのものを格納する添付ファイル型があります。どちらもPostgreSQLに直接対応する型がありません。当社の検証でも、初期(2026年7月21日時点)に変換が止まっていたクエリの多くは、この2つのデータ型が原因でした。
対処は教科書どおりの正規化です。複数値フィールドは「親ID・値」の子テーブル(中間テーブル)に切り出し、「この値を含む」という条件はEXISTSや結合で書き直します。添付ファイル型は、ファイルの置き場所自体を設計し直します(データベース外のストレージに置いてパスやキーを持つのが定石です)。
見落としやすいのは、分割の影響が「SELECT *」を使うクエリへ波及することです。分割前のテーブルを「*」で参照しているクエリは、分割後は列構成が食い違います。当社の検証では、「*」を分割後に残る列の明示リストへ展開し、落とした列は注記として開示する扱いにしました。テーブルを直すだけでは終わらず、そのテーブルを参照するクエリまで棚卸しが要る、と見ておいてください。
Nz・IIf・FormatはSQL標準の外にある関数
AccessのクエリではNzやIIfを式の中に書けますが、これらはSQL標準の関数ではないため、PostgreSQLにはそのまま持ち込めません。特にNzはAccess本体の関数(Application.Nz)で、当社の検証では、Nzを含むクエリをAccessアプリケーションを介さずデータベースエンジンだけで実行しようとして「未定義関数」エラーになり、実行経路を変えて初めて結果が取れた、というつまずきがありました。同じSQLでも実行経路によって使える関数が変わる点には、移行前の動作確認でも足を取られます。
PostgreSQLへの移し先は機械的に対応が付きます。Nz(NULLなら代替値)はCOALESCE、IIfはCASE式に対応します。ただし細部の評価挙動まで同一とは限らないので、書き換えたら結果を突き合わせて確かめる前提で進めてください。一方Formatは、値を書式に従って文字列化する表示の関心事なので、SQLに残さずReact側(画面の表示フォーマット)へ移すのが自然だと当社は考えています。日付や金額の見た目をSQLで文字列化してしまうと、並び替えや再集計がしにくいWeb画面になりがちです。
Date()を含むクエリは「誰の今日か」を決めてから移す
VBAのDate関数はそのPCのシステム日付を返します。一方PostgreSQLのCURRENT_DATEなどの現在日時関数はトランザクション開始時刻に基づき、返る「今日」は接続側のタイムゾーン設定(TimeZoneパラメータ)で決まります。つまりAccessでは「操作しているPCの今日」だったものが、移行後は「サーバーの今日」に変わり得ます。
当社の検証では、77本のうち「Year(Date())」「DatePart("q", Date())」を含む2本だけが、タイムゾーンを日本時間と明示して初めて変換を確定できました。日本とアメリカ西海岸では日付の変わり目が半日以上ずれるため、タイムゾーンの扱いを曖昧にしたまま移すと、「同じクエリなのに日をまたぐタイミングで新旧の集計結果が食い違う」形で表面化します。年度・四半期の集計にDate()系の関数を使っているクエリは、移行時に必ず洗い出しておくべき対象です。
パラメータクエリとフォーム参照は、プレースホルダとアプリ層へ
実行時に値を尋ねるパラメータクエリと、開いているフォームの入力値を参照する[Forms]![フォーム]![コントロール]形式のクエリは、値が束縛されて初めて結果が決まります。PostgreSQL側ではプレースホルダ(実行時に値を渡す穴)を持つSQLにし、値はアプリ層(React画面の検索条件をAPI経由で渡す形)から供給する設計になります。フォームとクエリが一体だったAccessと違い、「どの画面のどの入力が、どのSQLのどの穴に入るか」の対応表を移行時に作ることになります。
検証の実務で役に立ったのは、こうしたクエリの新旧比較を「NULL・境界値・実在するID」の3通りの値で行うことです。実在するIDでは行が返ることを、NULLや境界値では両側が同じように空になることを確かめると、「たまたま両方0行で一致した」だけの見せかけの一致を除外できます。値を入れないと動かないクエリの検証は後回しになりがちですが、画面の検索・絞り込みの本体なので、ここを飛ばすと移行後に一番使われる機能が未検証のまま残ります。
React側の注意は、Accessのフォームに埋まっていた関心事の分担
データベース側の論点に比べると、React側は選択の自由度が高く「正解が1つ」ではありません。ただ方針として、Accessのフォームに混在していた関心事を分けることをおすすめしています。表示フォーマット(Format相当)と入力補助はReact側へ、業務ルール(在庫を引き当ててよいか等)はAPI側へ、データの整合性制約(一意・参照整合)はPostgreSQL側へ、という分担です。Accessではこの3つがフォームとクエリの中に一体で埋まっていることが珍しくないので、どこへ何を移したかの対応が追える形にしておくと、移行後の保守が楽になります。画面の形も1対1では移りません。たとえばAccessの連続フォーム(帳票形式)は、Reactでは一覧コンポーネントと詳細画面の2つに分ける構成が候補になります。
構成全体の考え方はAccessのデータにWebフロントを付ける設計パターン、PostgreSQLの型変換・文字コードはPostgreSQL移行の技術ポイントもあわせて参照してください。手元のAccessにこの記事の「詰まりやすい箇所」がどれだけ含まれているかを把握したい場合は、無料の解析可否チェックから始められます。
よくある質問
Q. フロントがReactでなくても、この記事の内容は当てはまりますか。
当てはまります。この記事の論点の大半はPostgreSQL側(データ型・関数・日付・パラメータ)の話で、フロントがVueでも他のフレームワークでも同じです。フロント技術の選び方はWebシステム化の記事を参照してください。
Q. 自分のAccessに複数値フィールドや添付ファイル型があるか、どう調べればよいですか。
テーブルをデザインビューで開き、データ型が「添付ファイル」の列と、ルックアップタブで「複数の値を許可」が「はい」の列を探してください。テーブル数が多い、あるいはファイルに触れる人がいない場合は、解析で機械的に棚卸しする方法もあります。
Q. 移行後、新旧で同じ結果が出るかはどう確かめればよいですか。
クエリ単位で件数→集計値→行の値の順に突き合わせるのが基本です。当社の検証でも最終的な判定は「行の値まで一致するか」で行いました。並行稼働期間のデータ突合は並行稼働の設計の記事で扱っています。
Q. ここに書かれていない「詰まりどころ」はありますか。
あります。この記事は公開サンプル1本の検証で実際に手が掛かった箇所に絞ったもので、実案件のAccessには帳票・VBAイベント・外部連携など、ここに載っていない論点が構成次第で加わります。網羅的な洗い出しは解析の仕事になるため、まず現状のファイルで何が使われているかを把握するところから始めることをおすすめします。
解析可否の無料チェックのご案内
保守が難しくなったAccessについて、解析が可能かどうかのみを無料でご確認いただけます。顧客データの送信は不要で、発注義務もございません。
所要約2分・ファイル送信不要・発注義務はございません/ご説明はオンラインにて承ります