SQLite/ja: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: SQLite/ja
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## SQLite と FPC/Lazarus によるサポートについて | |
| 2 | + | ||
| 3 | + | SQLiteは、FPCとLazarusアプリケーションで使用できる組み込み(非サーバー)の単一ユーザーデータベースである。さまざまなドライバーを使用して、FPC/LazarusプログラムからSQLiteにアクセスできる。すべてのドライバーは、動作するために実行可能ディレクトリ(プロジェクトディレクトリまたはLazarusプロジェクト設定に依存する)にSQLiteライブラリ/dllが必要である(および実行可能ファイルと一緒に配布される)。 | |
| 4 | + | ||
| 5 | + | Win64: FPC/Lazarus Win64に関しては、特定のFPC/Lazarus Win64バージョンを使用しないようにすることに関する[[Windows Programming Tips|警告がある]]。 | |
| 6 | + | ||
| 7 | + | ### SQLite への直接アクセス | |
| 8 | + | ||
| 9 | + | LiteDAC(SQLite Data Access Components)は、Lazarus(およびFree Pascal)からWindows、Mac OS X、iOS、Android、Linux、FreeBSDの32ビットおよび64ビットプラットフォームに対して、SQLiteへのネイティブ接続を提供するコンポーネントのライブラリである。LiteDACは、プログラマーが追加のライブラリをデプロイすることなく、真にクロスプラットフォームなデスクトップおよびモバイルSQLiteデータベースアプリケーションを開発できるように設計されている。 | |
| 10 | + | ||
| 11 | + | 商業的な製品のトライアルバージョンを以下でダウンロードできる: [Lazarus components](https://www.devart.com/litedac/download.html) | |
| 12 | + | ||
| 13 | + | ### ビルトインの SQLDB | |
| 14 | + | ||
| 15 | + | FPC/Lazarusには、組み込みのSQLDBコンポーネントが含まれており、これにはSQLiteデータベースへのサポート([[TSQLite3Connection/ja]])が含まれている。これは[[Component Palette/ja|Component Palette/jaの]][[SQLdb tab/ja|SQLdb tab/jaからアクセスでき]]、例えば[[TDBGrid/ja|TDBGrid/jaなどのデータベースコンポーネントを]]使用したGUIを作成することができる。SQLDBを使用する利点は、プログラムをあまり変更することなく、FirebirdやPostgreSQLなどの異なるデータベースに簡単に変更できる。 | |
| 16 | + | ||
| 17 | + | 詳細は以下を参照のこと | |
| 18 | + | ||
| 19 | + | #### Spatialiteサポート | |
| 20 | + | ||
| 21 | + | Spatialiteは、SQLiteにGIS(地理情報システム)機能を追加したもので、SQLDB内から使用することができる。詳細については、[[Spatialite|Spatialiteを]]参照のこと。 | |
| 22 | + | ||
| 23 | + | #### SQLiteの暗号化のサポート | |
| 24 | + | ||
| 25 | + | 最近のFree Pascal Compiler(FPC)のバージョンでは(2012年3月に実装された)、SQLDBはSQLite3の拡張バージョンのいくつかをサポートしており、これによりSQLiteデータベースファイルをAESアルゴリズムを使用して暗号化することができる。暗号化キーを設定するには、パスワードプロパティを使用する。 | |
| 26 | + | ||
| 27 | + | Examples: | |
| 28 | + | ||
| 29 | + | - [SQLCipher](http://sqlcipher.net/): オープンソース、例えば、Windows用バイナリは無料ではない(自身でコンパイルする必要がある) | |
| 30 | + | - [System.Data.SQLite](http://system.data.sqlite.org/): オープンソース、Windows (32, 64, CE) バイナリが利用できる。コンパイルされたバイナリの1つをダウンロードし、SQLite.Interop.dllをsqlite3.dllにリネームする(もし静的にリンクしているのであれば、System.Data.SQLite.DLLをsqlite3.dllにリネームする必要がある) | |
| 31 | + | - [wxSQLite3](http://wxcode.sourceforge.net/docs/wxsqlite3/): オープンソース、Linuxに対するいくつかのバイナリが利用できる(例えば: <https://launchpad.net/ubuntu/oneiric/+package/libwxsqlite3-2.8-0>) | |
| 32 | + | ||
| 33 | + | #### sqlite3backup | |
| 34 | + | ||
| 35 | + | sqlite3backupは、FPCに提供されているユニットであり、Lazarusには含まれていないが、プログラムで使用することができる。これは、SQLite3のバックアップ/リストア機能を提供する。sqlite3backupは、SQLDBのsqlite3connを使用する。 | |
| 36 | + | ||
| 37 | + | ### Zeos | |
| 38 | + | ||
| 39 | + | [Zeos](https://sourceforge.net/projects/zeoslib/) | |
| 40 | + | ||
| 41 | + | ### SQLitePass | |
| 42 | + | ||
| 43 | + | [SqlitePass](http://source.online.free.fr/) components. Status: unknown. | |
| 44 | + | ||
| 45 | + | ### TSQLite3Dataset と TSQLiteDataset | |
| 46 | + | ||
| 47 | + | TSQLiteDataset(sqlitedsユニット)およびTSQLite3Dataset(sqlite3dsユニット)パッケージも提供されてる。APIリファレンス、チュートリアルに関しては使用法は以下を参照のこと [sqlite4fpc homepage](http://sqlite4fpc.yolasite.com/) | |
| 48 | + | ||
| 49 | + | TSQLiteDatasetとTSQLite3Datasetは、それぞれ2.8.xおよび3.x.xのSQLiteデータベースにアクセスする、[[TDataSet|TDataSetの]]派生クラスである。新しいプロジェクトでは、SQLite 3.xが現在のバージョンであるため、TSQLite3Datasetを使用することが一般的である。 | |
| 50 | + | ||
| 51 | + | 他のFPC/LazarusのSQLiteドライバやアクセス方法と比較した場合の主な利点と欠点は次のとおりである: | |
| 52 | + | ||
| 53 | + | 利点: | |
| 54 | + | ||
| 55 | + | - 柔軟性: プログラマーはSQL言語を使用するかどうかを選択できる。これにより、シンプルなテーブルレイアウトやSQL/sqliteで許可されている任意の複雑なレイアウトで作業できる。 | |
| 56 | + | ||
| 57 | + | 欠点: | |
| 58 | + | ||
| 59 | + | - 他のデータベースに変更する際、SQLDBやZeosコンポーネントを使用する場合よりも、変更がより困難になる。 | |
| 60 | + | ||
| 61 | + | > **Note:** 上記の情報から、多くのユーザーはSQLDBやZeosを利用することが一般的である。これらのツールを利用することで、SQLiteデータベースへの簡単な接続や操作が可能になる。 | |
| 62 | + | ||
| 63 | + | ## SQLiteでSQLdbコンポーネントを使用する | |
| 64 | + | ||
| 65 | + | これらの手順は、特にSQLiteデータベースのSQLDBコンポーネント、特にTSQLite3Connectionの利用に焦点を当てている。SQLDBコンポーネントやそれらの使用方法についてより包括的に理解するには、[[SqlDBHowto|SqlDBHowto/jaを]]参照のこと。これには、LazarusのSQLDBコンポーネントに関する一般的な概要や有用な情報が含まれている。 | |
| 66 | + | ||
| 67 | + | [[SQLdb Tutorial1/ja|SQLdb_Tutorial1/jaでは]]、SQLite/SQLDB(およびFirebird/SQLDB、PostgreSQL/SQLDBなど、SQLDBがサポートするほとんどのRDBMS)向けに書かれたGUIデータベース対応プログラムのチュートリアルを見ることができる。 | |
| 68 | + | ||
| 69 | + | LazarusのSQLdbタブから3つのコンポーネントの組み合わせを使用する: TSQLite3Connection、TSQLTransaction、TSQLQueryである。TSQLQueryはTDatasetとして機能し、最も単純な場合にはテーブルの1つを表します。単純化のために、既存のSQLiteデータベースファイルがすでに存在しており、新しいものを作成する必要がないことを確認してください。 TSQLite3Connectionは、自分で宣言したい場合やFreePascalで作業している場合は、*sqlite3conn*ユニットで見つけることができる。 | |
| 70 | + | ||
| 71 | + | 通常通り、これらの3つのコンポーネントは互いに接続される。TSQLQueryでは、DatabaseとTransactionのプロパティを設定する。TSQLTransactionでは、Databaseのプロパティを設定する。TransactionとConnectionのコンポーネントではあまりすることはない。興味深いことのほとんどは、TSQLQueryで行われます。以下のようにコンポーネントを設定する: | |
| 72 | + | ||
| 73 | + | TSQLite3Connection: | |
| 74 | + | ||
| 75 | + | - DatabaseName: このプロパティをSQLiteファイルのファイル名(絶対パス!)に設定します。残念ながら、単純に相対パスを使用してデザイン時とランタイム時で変更せずに動作する方法はない。***これはまだ真実か?ポストビルドのシェルスクリプトでdbファイルを単にコピーするか、シンボリックリンクを作成できない?***。デザイン時に含まれている内容に関係なく、常に正しいファイルへのパスがアプリケーション起動時にプログラムによって設定されていることを確認する必要がある。 | |
| 76 | + | ||
| 77 | + | 注意: フルライブラリパスを設定するには(Linux/OSXのアプリケーションディレクトリなど、OSがそれを見つけられない場所にsqliteのdll/so/dylibを配置した場合)、*SQLiteLibraryName*プロパティを設定できます(任意の接続が確立される前に、たとえばメインフォームのOnCreateイベント内で)以下のように: | |
| 78 | + | ||
| 79 | + | ``` pascal | |
| 80 | + | SQLiteLibraryName:='./sqlite3.so'; | |
| 81 | + | ``` | |
| 82 | + | ||
| 83 | + | TSQLQuery: | |
| 84 | + | ||
| 85 | + | - SQL: これをテーブルのいずれかに対するシンプルなselectクエリに設定する。例えば、テーブル 'foo' があり、このデータセットがこのテーブルを表すようにしたい場合は、以下を使用する: | |
| 86 | + | ||
| 87 | + | ``` SQL | |
| 88 | + | SELECT * FROM foo | |
| 89 | + | ``` | |
| 90 | + | ||
| 91 | + | - Active: IDE内でこれをTrueに設定して、すべてが正しく設定されているかどうかをテストする。これにより、トランザクションと接続オブジェクトも自動的にアクティブになる。エラーが発生した場合は、接続のDatabaseNameが正しくないか、SQLクエリが間違っている可能性がある。後で、フィールドを追加し終えた後(以下を参照)、すべてを再び非アクティブに設定してください。IDEがアプリケーションのテスト中にSQLiteデータベースをロックしないようにします(シングルユーザーで!)。 | |
| 92 | + | ||
| 93 | + | - *おそらく正常な動作には必要ないかもしれない - 確認する必要がある(2012年6月)*。これで、TSQLQueryにフィールドを追加できるようになった。コンポーネントがまだアクティブに設定されている間に、右クリックして「edit fields...」をクリックする。"+"ボタンをクリックしてフィールドを追加する。これにより、SQLクエリが返したすべてのフィールドが一覧表示される。必要なすべてのフィールドを追加し、ルックアップフィールドもここで追加できる。この場合、他のデータセットで必要なフィールドをすでに定義していることを確認した後、参照フィールドを追加することを開始すること。テーブルに多くの列がある場合で、すべてを必要としない場合は、それらは省略できる。SQLを少し具体的にすることもできる。 | |
| 94 | + | - コード内でSQLQuery.ApplyUpdatesおよびSQLTransaction.Commitを呼び出す必要がある。データ連動コントロールと一緒に使用する場合は、TSQLQuery.AfterPostおよびAfterInsertイベントが良い場所だが、もちろん、これらの呼び出しを後で行うこともできる。これらの呼び出しを行わない場合、データベースは更新されない。 | |
| 95 | + | - "Database is locked": IDEがまだデータベースをロックしているかもしれない(SQLiteはシングルユーザーデータベースである)。TSQLQueryオブジェクトのすべてのフィールドを定義した後に、コンポーネントを非アクティブにしてから切断するのを忘れた可能性がある。実行時にパスを設定し、オブジェクトをアクティブにするには、フォームのOnCreateイベントを使用する。IDE内でTSQLQueryに設定するほとんどの設定は、デザイン時にアクティブである必要はなく(一部はデザイン時にアクティブであってはいけない場合もある)、唯一の例外はフィールドの定義です。デザイン時に非アクティブであることが通常の状態であるべきである。 | |
| 96 | + | - テーブルはすべて主キーを持っている必要があり、対応するフィールドがpfInKeyのみであり、他のフラグがないようにする(これらのフラグは、自動的に更新クエリと削除クエリを構築する際にフィールドがどのように使用されるか、およびどこで使用されるかを制御する)。 | |
| 97 | + | - ルックアップフィールドを用いている場合 | |
| 98 | + | - ルックアップフィールドのProviderFlagsが完全に空であることを確認すること。これにより、更新クエリでその名前が使用されることはない。ルックアップフィールド自体はデータフィールドではなく、他のフィールド、つまり対応するキーフィールドの値にのみ作用し、後で更新クエリで使用されるのはこのキーフィールドのみである。通常、DBGridに表示したくないキーフィールドを非表示にすることができるが、定義する必要がある。 | |
| 99 | + | - LookupCacheをTrueに設定する必要がある。現時点では、なぜかルックアップフィールドはそれ以外の場合(しかし動作はする)に何も表示されないため、これを設定する必要がある。そして、奇妙なことに、TSQLite3Datasetや他のTXXXDatasetコンポーネントを使用する場合は正反対の設定にする必要がある。こちらではFalseに設定する必要がある。これが意図された動作なのか、それともバグなのかはまだ確信が持てない。 | |
| 100 | + | - 通常、シンプルなテーブルでは、InsertSQL、UpdateSQL、DeleteSQLのいずれのプロパティも設定する必要はない。これらを空のままにしておいてよい。すべてのフィールドのProviderFlagsが正しく設定されていれば、必要なSQLを動的に作成できるはずである。InsertSQL、UpdateSQL、DeleteSQLの詳細については、[[Working With TSQLQuery|Working_With_TSQLQuery#TSQLQuery.InsertSQL.2C_TSQLQuery.UpdateSQL_and_TSQLQuery.DeleteSQL:_Basic_Use_of_Parametersを]]参照のこと。 | |
| 101 | + | ||
| 102 | + | 上記の設定がすべて正しく行われている場合、TSQLQueryを他の任意のTDatasetと同様に使用できるはずである。プログラムでデータを操作するか、フォームにTDatasouceを配置し、それをTSQLQueryに接続してから、TDBGridなどのデータコントロールを使用することができる。 | |
| 103 | + | ||
| 104 | + | ### データベースを作る | |
| 105 | + | ||
| 106 | + | [TSQLite3Connection.CreateDB](http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnection.createdb.html)メソッドは親クラスから継承されたもので実際には何も行わない。まだファイルが存在しない場合にデータベースを作成するには、次の例のようにテーブルデータを書き込む必要がある。 (Lazarus 1.3以降で提供されているsqlite_encryption_pragmaの例から抜粋されたコード) | |
| 107 | + | ||
| 108 | + | ``` pascal | |
| 109 | + | var | |
| 110 | + | newFile : Boolean; | |
| 111 | + | begin | |
| 112 | + | ||
| 113 | + | SQLite3Connection1.Close; // 開始時はコネクションが閉じていることを保証する | |
| 114 | + | ||
| 115 | + | try | |
| 116 | + | // このデータベースは初めて作られているので | |
| 117 | + | // ファイルが既にあるかどうか確かめる | |
| 118 | + | newFile := not FileExists(SQLite3Connection1.DatabaseName); | |
| 119 | + | ||
| 120 | + | if newFile then | |
| 121 | + | begin | |
| 122 | + | // データベースとテーブルを作る | |
| 123 | + | try | |
| 124 | + | SQLite3Connection1.Open; | |
| 125 | + | SQLTransaction1.Active := true; | |
| 126 | + | ||
| 127 | + | // 「DATA」という名前の新しいデータベースを設定する | |
| 128 | + | SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+ | |
| 129 | + | ' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+ | |
| 130 | + | ' "Current_Time" DateTime NOT NULL,'+ | |
| 131 | + | ' "User_Name" Char(128) NOT NULL,'+ | |
| 132 | + | ' "Info" Char(128) NOT NULL);'); | |
| 133 | + | ||
| 134 | + | // DATAテーブルのidに基づいてインデクスを作る | |
| 135 | + | SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );'); | |
| 136 | + | ||
| 137 | + | SQLTransaction1.Commit; | |
| 138 | + | ||
| 139 | + | ShowMessage('Succesfully created database.'); | |
| 140 | + | except | |
| 141 | + | ShowMessage('Unable to Create new Database'); | |
| 142 | + | end; | |
| 143 | + | end; | |
| 144 | + | except | |
| 145 | + | ShowMessage('Unable to check if database file exists'); | |
| 146 | + | end; | |
| 147 | + | end; | |
| 148 | + | ``` | |
| 149 | + | ||
| 150 | + | ### ユーザー定義の照合順序を作成する | |
| 151 | + | ||
| 152 | + | ``` pascal | |
| 153 | + | // utf8 の大文字小文字を比較するコールバック関数 | |
| 154 | + | function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; | |
| 155 | + | var S1, S2: AnsiString; | |
| 156 | + | begin | |
| 157 | + | SetString(S1, data1, len1); | |
| 158 | + | SetString(S2, data2, len2); | |
| 159 | + | Result := UnicodeCompareStr(UTF8Decode(S1), UTF8Decode(S2)); | |
| 160 | + | end; | |
| 161 | + | ||
| 162 | + | // utf8 の大文字小文字を比較するコールバック関数 | |
| 163 | + | function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; | |
| 164 | + | var S1, S2: AnsiString; | |
| 165 | + | begin | |
| 166 | + | SetString(S1, data1, len1); | |
| 167 | + | SetString(S2, data2, len2); | |
| 168 | + | Result := UnicodeCompareText(UTF8Decode(S1), UTF8Decode(S2)); | |
| 169 | + | end; | |
| 170 | + | ||
| 171 | + | // SQLite3 APIを使用して照合順序を登録する(sqlite3dynユニットが必要): | |
| 172 | + | sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI); | |
| 173 | + | // もしくはTSQLite3Connectionのメソッドを使用: | |
| 174 | + | CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI); | |
| 175 | + | ||
| 176 | + | // ここでSQL様に大文字小文字を区別しない比較を用いることができる: | |
| 177 | + | // SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á' | |
| 178 | + | ||
| 179 | + | // これはLIKE演算子では機能しない | |
| 180 | + | // また、LIKE演算子をサポートするためには、sqlite3_create_function()を用いてデフォルトのLIKEをオーバーロードしなければならない | |
| 181 | + | // http://www.sqlite.org/lang_corefunc.html#like | |
| 182 | + | ``` | |
| 183 | + | ||
| 184 | + | ### ユーザー定義関数を作る | |
| 185 | + | ||
| 186 | + | ``` pascal | |
| 187 | + | // デフォルトの提供されたLOWER()関数をユーザーにオーバーロードする例 | |
| 188 | + | // このデモを実行するにはuses節に 'sqlite3dyn' と 'ctypes'を記述する必要がある | |
| 189 | + | // そして、定数'SQLITE_DETERMINISTIC'の値を$800とする | |
| 190 | + | ||
| 191 | + | procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl; | |
| 192 | + | var S: AnsiString; | |
| 193 | + | begin | |
| 194 | + | SetString(S, sqlite3_value_text(V[0]), sqlite3_value_bytes(V[0])); | |
| 195 | + | S := UTF8Encode(AnsiLowerCase(UTF8Decode(S))); | |
| 196 | + | sqlite3_result_text(ctx, PAnsiChar(S), Length(S), sqlite3_destructor_type(SQLITE_TRANSIENT)); | |
| 197 | + | end; | |
| 198 | + | ||
| 199 | + | // SQLite3 APIを用いてLOWER()関数を登録する(sqlite3dynユニットが必要である): | |
| 200 | + | sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil); | |
| 201 | + | ``` | |
| 202 | + | ||
| 203 | + | ### SQLite3 と 日付 | |
| 204 | + | ||
| 205 | + | - SQLite 3では、日付を特別なDateTime値として保存しない。代わりに、それらを文字列、倍精度浮動小数点数、または整数として保存できる。詳細については <http://www.sqlite.org/datatype3.html#datetimeを参照のこと> | |
| 206 | + | - 文字列では、日付の区切り記号はSQL標準/ISO 8601に従って '-' である。したがって、組み込みのDATE関数を使用してINSERTを行うと、'YYYY-MM-DD'のような形式で保存される。 | |
| 207 | + | - DateTime値を文字列として保存すると、DataSetsで問題が発生する可能性がある。.AsDateTime修飾子はSQLiteの「文字列日付」でスタックする可能性があるが、SQL SELECTステートメントで`strftime(`*`%d/%m/%Y`*`,recdate) AS sqlite3recdate`のようなものを使用することで、SQLite3に指定された形式で日付レコードを返すように指示できる(フォーマット文字列%d /%m /%dは、.AsDateTimeが理解するロケール日付形式に対応しています)。**==\> このような場合は、問題を示す例のアプリケーションを使用してバグレポートを作成してほしい** | |
| 208 | + | ||
| 209 | + | 日付を文字列として保存している場合(たとえばBETWEEN関数を使用して)、比較は常に**文字列**の比較になることを覚えておくこと。したがって、比較結果は日付値の保存方法に依存する。 | |
| 210 | + | ||
| 211 | + | #### UTCの代わりにローカルタイムをデフォルトに用いる | |
| 212 | + | ||
| 213 | + | CURRENT_TIME, CURRENT_DATE and CURRENT_TIMESTAMP は現在のUTC日付および、もしくは時刻を返す。ローカルの日付、および、または時刻を用いるために以下のようにする: | |
| 214 | + | ||
| 215 | + | ` DEFAULT (datetime('now','localtime')) for datetime values formated YYYY-MM-DD HH:MM:SS`\ | |
| 216 | + | ` DEFAULT (date('now','localtime')) for date value formated YYYY-MM-DD`\ | |
| 217 | + | ` DEFAULT (time('now','localtime')) for time value formated HH:MM:SS` | |
| 218 | + | ||
| 219 | + | ### SQLDB と SQLite のトラブルシューティング | |
| 220 | + | ||
| 221 | + | - デザイン時のサポート(フィールドなど)が機能するには、Lazarusがsqlite3.dllも見つける必要があることに注意すること。 | |
| 222 | + | - 同じことがデータベースのファイル名にも適用される。デザイン時にフィールド名などを抽出する場合は常に絶対パスを使用すること。そうしないと、IDEがそのディレクトリに空のファイルを作成する。問題が発生した場合は、lazarus/ディレクトリにデータベースファイルのゼロバイトコピーがないか確認すること。 | |
| 223 | + | - マスター/ディテール関係がある場合、スレーブデータセットの外部キーの値を取得するために、各挿入後にマスターデータセットを更新する必要がある。これは、マスターデータセットのAfterPostイベントで、次のオーバーロードされた手順のいずれかを呼び出すことで行うことができる: | |
| 224 | + | ||
| 225 | + | ``` pascal | |
| 226 | + | interface | |
| 227 | + | procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);overload; | |
| 228 | + | procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);overload; | |
| 229 | + | ||
| 230 | + | implementation | |
| 231 | + | ||
| 232 | + | procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string); | |
| 233 | + | ||
| 234 | + | //このプロシージャはデータセットをリフレッシュし、カーソルを最後のレコードに配置する | |
| 235 | + | //データセットが自動インクリメントの主キーでソートされていることが保証されていない場合に使用する必要がある | |
| 236 | + | var | |
| 237 | + | vLastID: Integer; | |
| 238 | + | vUpdateStatus : TUpdateStatus; | |
| 239 | + | begin | |
| 240 | + | vUpdateStatus := pDataset.UpdateStatus; | |
| 241 | + | //データベースに最後に挿入されたIDを取得 | |
| 242 | + | pDataset.ApplyUpdates; | |
| 243 | + | vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID; | |
| 244 | + | //ここで、それぞれの行に戻る | |
| 245 | + | if vUpdateStatus = usInserted then begin | |
| 246 | + | pDataset.Refresh; | |
| 247 | + | //それぞれの行に戻り、リフレッシュする | |
| 248 | + | pDataset.Locate(pKeyField,vLastID,[]); | |
| 249 | + | end; | |
| 250 | + | end; | |
| 251 | + | ||
| 252 | + | procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery); | |
| 253 | + | //このプロシージャはデータセットをリフレッシュし、カーソルを最後のレコードに配置する | |
| 254 | + | //データセットが自動インクリメントの主キーでソートされていることが保証されていない場合に使用する必要がある | |
| 255 | + | var | |
| 256 | + | vLastID: Integer; | |
| 257 | + | vUpdateStatus : TUpdateStatus; | |
| 258 | + | begin | |
| 259 | + | vUpdateStatus := pDataset.UpdateStatus; | |
| 260 | + | pDataset.ApplyUpdates; | |
| 261 | + | vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID; | |
| 262 | + | if vUpdateStatus = usInserted then begin | |
| 263 | + | pDataset.Refresh; | |
| 264 | + | //危険! | |
| 265 | + | pDataSet.Last; | |
| 266 | + | end; | |
| 267 | + | end; | |
| 268 | + | ||
| 269 | + | procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet); | |
| 270 | + | begin | |
| 271 | + | RefreshADatasetAfterInsert(Dataset as TSQLQuery); //もしデータセットがプライマリキーでソートされているなら | |
| 272 | + | end; | |
| 273 | + | ||
| 274 | + | procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet); | |
| 275 | + | begin | |
| 276 | + | RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //もしデータセットがプライマリキーでソートされていることが不確かなら | |
| 277 | + | end; | |
| 278 | + | ``` | |
| 279 | + | ||
| 280 | + | ### トランザクションとは別に行われるべきVacuum と 他のオペレーション | |
| 281 | + | ||
| 282 | + | SQLDBは常に接続を必要とするようだが、PragmaやVacuumなどの一部の操作はトランザクションの外で行う必要がある。トランザクションを終了し、必要な操作を実行し、再びトランザクションを開始するトリックを使用する(これにより、SQLDBが混乱しないようする)。 | |
| 283 | + | ||
| 284 | + | ``` pascal | |
| 285 | + | // ペンディング中のすべてのオペレーションをコミットするか、"fresh" sqlconnectionをもちいる | |
| 286 | + | Conn.ExecuteDirect('End Transaction'); // SQLdbによって開始されたトランザクションを終える | |
| 287 | + | Conn.ExecuteDirect('Vacuum'); | |
| 288 | + | Conn.ExecuteDirect('Begin Transaction'); //SQLdbが用いるためトランザクションを開始 | |
| 289 | + | ``` | |
| 290 | + | ||
| 291 | + | ## TSQLite3Dataset を使う | |
| 292 | + | ||
| 293 | + | この節では、SQLite データベースへアクセスするために、どのように TSQLite2Dataset または TSQLite3Dataset コンポーネント を用いるかを詳しく説明しています。 Luiz Américo による luizmed(at)oi(dot)com(dot)br | |
| 294 | + | ||
| 295 | + | #### 要求事項 | |
| 296 | + | ||
| 297 | + | - sqlite2 データベースのためには(レガシー): | |
| 298 | + | - FPC 2.0.0 以上 | |
| 299 | + | - Lazarus 0.9.10 以上 | |
| 300 | + | - SQLite runtime library 2.8.15 以上* | |
| 301 | + | ||
| 302 | + | - Sqlite2 はもはやメインテナンスされておらず、sqlite のサイトでバイナリファイルを見つけることはできません。 | |
| 303 | + | ||
| 304 | + | - sqlite3 データベースのためには: | |
| 305 | + | - FPC 2.0.2 以上 | |
| 306 | + | - Lazarus 0.9.11 (svn revision 8443) 以上 | |
| 307 | + | - SQLite runtime library 3.2.1 以上 ([www.sqlite.org](http://www.sqlite.org) から入手してください。) | |
| 308 | + | ||
| 309 | + | **Lazarus のプロジェクトを作る前に、次の事を確認してください。:** | |
| 310 | + | ||
| 311 | + | - SQLite ライブラリが | |
| 312 | + | - システム PATH にある | |
| 313 | + | - 実行ファイルの出力されるディレクトリと Lazarus(または現在のプロジェクトの)ディレクトリにある - このオプションは Windows のみです。 | |
| 314 | + | - Linuxでは、cmemを メインプログラムの uses の最初のユニットにしているかどうか | |
| 315 | + | - Debian や Ubuntu またその他の Debian-like ディストロにおいては、Lazarus IDE に libsqlite-dev/libsqlite3-dev, not only sqlite/sqlite3 パッケージをインストールする必要があります。(OpenSuSe にも適用してください。) | |
| 316 | + | ||
| 317 | + | ### 使い方 (基本) | |
| 318 | + | ||
| 319 | + | /components/sqlite にあるパッケージをインストールしてください。([[Install Packages/ja|ここにその]]方法があります。) | |
| 320 | + | ||
| 321 | + | 設計時に下記のプロパティをセットして下さい。 | |
| 322 | + | ||
| 323 | + | - FileName: sqliteファイルへのパス\[必須\] | |
| 324 | + | - TableName: sql文で使うテーブル名\[必須\] | |
| 325 | + | - SQL: SQLのSELECT文 \[必要に応じて\] | |
| 326 | + | - SaveOnClose: デフォルト値はfalse。つまり変更は保存されない。trueに変更可能。 \[必要に応じて\] | |
| 327 | + | - Active: 設計時またはプログラムのスタート時に設定\[必須\] | |
| 328 | + | ||
| 329 | + | **テーブルを作成する(Dataset)** | |
| 330 | + | ||
| 331 | + | コンポーネントアイコンをダブルクックするか、右マウスボタンのクリックで現れるポップアップメニューより、'Create Table' を選択します。 簡単な説明のあるテーブルエディタが表示されます。 | |
| 332 | + | ||
| 333 | + | 下記は TSqliteDataset と TSqlite3Dataset でサポートされているすべてのフィールドの型です。 | |
| 334 | + | ||
| 335 | + | - Integer | |
| 336 | + | - AutoInc | |
| 337 | + | - String | |
| 338 | + | - Memo | |
| 339 | + | - Bool | |
| 340 | + | - Float | |
| 341 | + | - Word | |
| 342 | + | - DateTime | |
| 343 | + | - Date | |
| 344 | + | - Time | |
| 345 | + | - LargeInt | |
| 346 | + | - Currency | |
| 347 | + | ||
| 348 | + | **データを取得する** | |
| 349 | + | ||
| 350 | + | テーブルを生成した後か、以前作ったテーブルで作業する場合、Open 手続きでデータセットを開いて下さい。 SQL プロパティがセットされていない場合、すべてのフィールドのすべてのレコードを取得するためには、次のような1文をSQLにセットします。: | |
| 351 | + | ||
| 352 | + | ``` pascal | |
| 353 | + | SQL := 'Select * from TABLENAME'; | |
| 354 | + | ``` | |
| 355 | + | ||
| 356 | + | **データファイル上に変更を適用する** | |
| 357 | + | ||
| 358 | + | ApplyUpdates 関数を使うために, データセットは、主キーの条件を満たす少なくとも1つのフィールドを持っていなければなりません。(値は、UNIQUE であり、NULL ではない必要があります。) | |
| 359 | + | ||
| 360 | + | 変更を適用するために2つの方法があります。 | |
| 361 | + | ||
| 362 | + | - PrimaryKey プロパティに主キーになっているフィールド名を設定する。 | |
| 363 | + | - AutoIncフィールドを加える。(これは TSqliteDataset が自動的にそれを主キーとしてみなすので、より簡単です。) | |
| 364 | + | ||
| 365 | + | 2つの条件のうち1つをセットしたら、以下を呼び出してください。 | |
| 366 | + | ||
| 367 | + | ``` pascal | |
| 368 | + | ApplyUpdates; | |
| 369 | + | ``` | |
| 370 | + | ||
| 371 | + | > **Note:** もし、両方の条件がセットされたら、主キーに相当するフィールドが更新の適用に使われます。 | |
| 372 | + | ||
| 373 | + | > **Note:** 主キーではないフィールドを主キーに設定することは、ApplyUpdate がコールされたときにデータのロスを引き起こします。ですから、選択されたフィールドは、 Null でなく Unique であることを、それを使う前に確認してください。 | |
| 374 | + | ||
| 375 | + | ##### Master/detail のサンプル | |
| 376 | + | ||
| 377 | + | master/detail 関係の様々なサンプル (例えば、顧客と注文の間の関係): | |
| 378 | + | ||
| 379 | + | - `DataSource` プロパティを用いての一般的な SQLDB での方法 : [[MasterDetail/ja]] | |
| 380 | + | - locate を用いた TSQLite3 に特徴的なサンプル : [[TSqlite3 Master Detail Example/ja]]. | |
| 381 | + | ||
| 382 | + | #### 注意事項 | |
| 383 | + | ||
| 384 | + | - 10000レコードまではテストして、上手く動きますが、TSqliteDataset はすべてのデータをメモリ上に置くため、必要なデータのみ受け取るようにしてください。(特にMemoフィールドなどに注意). | |
| 385 | + | - 同じデータファイルに(同じファイル名のプロパティに)、いくつかのテーブル、データセットを持たせることができます。 | |
| 386 | + | - いくつかのデータセット(違うフィールドの組み合わせの)を同じテーブルから作ることができます。 | |
| 387 | + | - SQL文 で WHERE を使ってデータをフィルタすることが可能です。また、データセットのクローズおよび再オープン(あるいは、RefechData メソッドを呼ぶこと)ができます。しかし、この場合、並び順やフィールドの数は同じでなくてはなりません。 | |
| 388 | + | - 複数のテーブルから aliases や join , views などを使って複雑な SQL 文が実行可能です(これらは同じデータファイルにある必要があることに注意)。しかしこの場合、ApplyUpdate は動作しません。もし複雑なクエリをつかって、データファイルに更新を加えたければ私(Luiz Américo)にメールしてください。そうすれば、どういうふうにおこなうか、ヒントをお伝えすることができます。 | |
| 389 | + | - TSqliteDataset で生成されていない sqlite のデータファイルにファイル名を設定するときおよび、そのファイルを開くとき、一部のフィールドが正しい型を検出することが、許可されていません。これらは、string フィールドとして扱われます。 | |
| 390 | + | ||
| 391 | + | 一般的なサンプルが、SVNディレクトリの fpc/fcl-db/src/sqlite にあります。 | |
| 392 | + | ||
| 393 | + | ## 関連情報 | |
| 394 | + | ||
| 395 | + | - [[SQLdb Tutorial1/ja]] Sqlite のためのチュートリアル | |
| 396 | + | - [[SqlDBHowto/ja]] General SQLDB についての情報 | |
| 397 | + | - [[Working With TSQLQuery/ja]] SQLDB の TSQLQuery についての情報 | |
| 398 | + | - [SQLite site](http://www.sqlite.org) | |
| 399 | + | ||
| 400 | + | --- | |
| 401 | + | *From the Free Pascal wiki, page "SQLite/ja", as it stood on 2024-03-26 after a change by Ariben, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
