ローカル SQL(FireDAC)
コマンドの操作(FireDAC) への移動
概要
ローカル SQL 機能を使用すると、DB テーブルの代わりに TDataSet の下位クラスを使用して SQL コマンドを実行することができます。ローカル SQL は、SQLite データベースが基礎になっており、ほとんどの SQLite SQL ダイアレクトがサポートされています。TDataSet の名前(Name プロパティの値)または指定された名前がテーブル名として使われます。クエリ可能なデータセットは、ローカル SQL エンジンである TFDLocalSQL に登録しなければなりません。
読み取り操作や書き込み操作はすべて、TDataSet API とその拡張機能を使って行われます。このエンジンでは、FireDAC と非 FireDAC のデータセットをサポートしています。ローカル SQL は、FireDAC データセットを使用した場合の方が効率的です。あるいは、非 FireDAC データセットの場合には、IFDPhysLocalQueryAdapter インターフェイスをアダプタ クラスとして実装し、ローカル SQL エンジンに登録することができます。
ローカル SQL の適用方法には次のようなものがあります。
- 異種クエリ(さまざまな DB から取得した結果セットをクエリ可能なデータセットに保持します)。
- インメモリ データベース(TFDMemTables がデータセットの役割をします)。
- 拡張オフライン モード。この場合、メイン DB にはアクセスできませんが、アプリケーションが SQL クエリを実行することはできます。
- 拡張 DataSnap クライアント(DataSnap ドライバからクライアントに配信されたデータに対してローカルでクエリを実行できます)。
- 移行の簡略化。アプリケーションでサードパーティの TDataSet オブジェクトを使用し、FireDAC API によってそのデータ ソースを扱うことができます。
構成
FireDAC は、SQLite ドライバをローカル SQL エンジンとして使用します。そのため、アプリケーションではまず、SQLite の "ローカル" 接続が必要です。これは、インメモリ接続のような、ファイルベースの読み書き接続でもかまいません。インメモリ接続の使用をお勧めします。セットアップは以下の手順で行います。
- フォームに TFDPhysSQLiteDriverLink コンポーネントをドロップします。
- TFDConnection をドロップします。
- その DriverName を SQLite に設定します。
アプリケーションでは、データセットをローカル SQL エンジンに接続する必要があります。手順は以下のとおりです。
- フォームに TFDLocalSQL コンポーネントをドロップします。
- その Connection プロパティをローカル SQLite 接続オブジェクトに設定します。
- データセットの Name プロパティを確認し、必要であれば値を割り当てます。このステップが必要なのは、コード内で動的にデータセットを作成する場合です。
- FireDAC データセットの場合、TFDAdaptedDataSet.LocalSQL プロパティを TFDLocalSQL インスタンスに設定します。
- あるいは、FireDAC と非 FireDAC データセットの両方を使用する場合には、TFDLocalSQL.DataSets コレクションを使用して、TDataSet とアダプタ(オプション)をローカル SQL エンジンに登録します。また、DataSets コレクションを使用すると、代替データセット名を指定することができます。
最後に、以下のオブジェクトをアクティブ化します。
- ローカル SQLite 接続を有効化します。
- TFDLocalSQL.Active を True に設定してローカル SQL エンジンを有効化します。
- メモ: アプリケーションで、同じ SQLite 接続に接続された基底データセットとローカル データセットを使用している場合には、その接続を使用しているいずれかのデータセットを開いたり実行したり準備する前に、明示的に接続を有効化する必要があります。そうでなければ例外が発生します。
あるいは、TFDLocalSQL.OnGetDataSet イベント ハンドラを使用して、データセットをローカル SQL エンジンに送信することができます。
ローカル接続とローカル SQL エンジンの両方がアクティブになると、関連するすべてのデータセットがエンジンに登録されます。新しいデータセットを関連付ける時に何かを開き直す必要はなく、データセットは自動的に登録されます。登録されると、データセットは開きます。TFDMemTable には、開く前に構造を定義しておかなければなりません。アプリケーションで大量のデータセットを登録する場合には、登録前にローカル SQL エンジンを非アクティブ化し、登録後にアクティブ化することをお勧めします。
アプリケーションで TFDLocalSQL.SchemaName をスキーマ プレフィックスに設定し、それを SQL クエリ内で使用することができます。複数の TFDLocalSQL を同じ接続に接続して使用することができますが、そのときにスキーマ名を指定してもしなくてもかまいません。ただし、1 つの SQLite 接続内では、それぞれの TFDLocalSQL.SchemaName が一意でなければなりません。スキーマ名によってデータセットを論理グループに整理することができます。スキーマ名を指定すると、SQL コマンド内でデータセットを <データセット名> または <スキーマ名>.<データセット名> として参照することができます。
必要であれば、アプリケーションで TFDLocalSQL.MultipleCursors を False に設定して、データセットの複製やコピーを避けることができます。SQLite では、カーソルを作成して、データセットを参照する SQL コマンドを実行します。TDataSet API では 1 つの位置しか保持できません。その制限を回避するために、FireDAC では TFDMemTable を使って FireDAC データセットを複製したり、非 FireDAC データセットを TFDMemTable にコピーします。データセットが 1 秒に 1 度しか使われないことが確かであれば、MultipleCursors を False に設定してパフォーマンスを向上することができます。単方向データセットが存在する場合には、MultipleCursors を False に設定することはお勧めできません。
クエリ実行
ローカル SQL クエリを実行するには、アプリケーションで TFDQuery/TFDCommand を使用し、Connection/ConnectionName をローカル SQLite 接続(TFDLocalSQL.Connection にも設定されているもの)に設定しなければなりません。これで、ローカルでない SQL 接続の場合と同様に SQL クエリを実行することができます。
クエリを処理している間、クエリ可能なデータセットは DisableControls によって無効化され、処理が完了すると有効化されます。データセットを有効なままにするには、TFDLocalSQL.DisableControls を False に設定します。 データセットを読み取る前に TFDLocalSQL.OnOpenDataSet イベント ハンドラが呼び出されます。
ローカル SQL エンジンでは SQLite SQL ダイアレクトをサポートしていますが、いくらか制限があります。TDataSet データ ソースの場合には、以下の SQL コマンドがサポートされていません。
- ALTER TABLE ... ADD COLUMN。その代わりに、データセット構造を変更してください。
- DROP TABLE。データセットは、ローカル SQL エンジンから切り離すと、自動的に(解放ではなく)削除されます。
- CREATE INDEX/DROP INDEX。SQL インデックスの代わりにデータセット インデックスを使用してください。
- CREATE TRIGGER/DROP TRIGGER。トリガの代わりにデータセット イベントを使用してください。
ローカル SQL エンジンでは、複数の結果セットを含むデータセットをサポートしていません。
ローカル SQL エンジンでは、INSERT/UPDATE/DELETE の SQL コマンドを、トランザクションおよびセーブポイントとしてサポートしています。また、対応する SQL コマンドは TDataSet API 呼び出しに変換されます。
ローカル SQL エンジンでは INSERT OR REPLACE をサポートしていますが、主キーまたは一意キーの制約の違反があると、置換対象レコードの検索に主キー フィールドしか使われません。さらに、INSERT OR REPLACE INTO <テーブル> (<フィールド リスト>) で一部のフィールドしか指定されていない場合、指定されていないフィールドは更新時に NULL 値になります。
互換性
ローカル SQL エンジンでは、TDataSet API を IFDPhysLocalQueryAdapter インターフェイスによって拡張して使用しています。FireDAC データセットはこのインターフェイスを実装しています。さらに、非 FireDAC データセットの場合に必要であれば、このインターフェイスを実装するクラスを作成し、そのインスタンスを TFDLocalSQL.DataSets[..].Adapter プロパティに割り当てることができます。
また、ローカル SQL 操作を実行するには、データセットが以下の要件を満たしている必要があります。
操作 | 要件 |
---|---|
INSERT | 必須:
任意:
|
UPDATE | 必須:
任意:
|
DELETE | 必須:
任意:
|
ソート/ORDER BY | 任意:
|
フィルタリング/WHERE | 任意:
|
セーブポイント | 必須:
|
トランザクション | 必須:
|
例 1
以下に示すのは、SQL Anywhere および Oracle のテーブルと FireDAC の TFDQuery を使用した異種クエリです。
// setup connection and query to "Orders" table in SQL Anywhere DB
FDConnection1.ConnectionDefName := 'ASA_Demo';
FDConnection1.Connected := True;
FDQuery1.Connection := FDConnection1;
FDQuery1.SQL.Text := 'select * from Orders';
// link dataset to Local SQL engine
FDQuery1.LocalSQL := FDLocalSQL1;
// setup connection and query to "Order Details" table in Oracle DB
FDConnection2.ConnectionDefName := 'Oracle_Demo';
FDConnection2.Connected := True;
FDQuery2.Connection := FDConnection2;
FDQuery2.SQL.Text := 'select * from "Order Details"';
// link dataset to Local SQL engine
FDQuery2.LocalSQL := FDLocalSQL1;
// setup SQLite in-memory connection
FDConnection3.DriverName := 'SQLite';
FDConnection3.Connected := True;
// link Local SQL to SQLite connection
FDLocalSQL1.Connection := FDConnection3;
FDLocalSQL1.Active := True;
// execute SELECT query on above datasets
FDQuery3.Connection := FDConnection3;
FDQuery3.SQL.Text := 'SELECT * FROM FDQuery1 LEFT JOIN FDQuery2 ON FDQuery1.OrderID = FDQuery2.OrderID';
FDQuery3.Active := True;
例 2
以下に示すのは、ADO の TADOQuery と FireDAC の TFDQuery を使用した異種クエリです。
// setup connection and query to "Orders" table
ADOQuery1.SQL.Text := 'select * from Orders';
// link dataset to Local SQL engine
with FDLocalSQL1.DataSets.Add do begin
DataSet := ADOQuery1;
Name := 'Orders';
end;
// setup connection and query to "Order Details" table
ADOQuery2.SQL.Text := 'select * from "Order Details"';
// link dataset to Local SQL engine
with FDLocalSQL1.DataSets.Add do begin
DataSet := ADOQuery2;
Name := 'Order Details';
end;
// setup SQLite in-memory connection
FDConnection1.DriverName := 'SQLite';
FDConnection1.Connected := True;
// link Local SQL to SQLite connection
FDLocalSQL1.Connection := FDConnection1;
FDLocalSQL1.Active := True;
// execute SELECT query on above datasets
FDQuery1.Connection := FDConnection1;
FDQuery1.SQL.Text := 'SELECT * FROM Orders o LEFT JOIN "Order Details" od ON o.OrderID = od.OrderID';
FDQuery1.Active := True;