Difference between revisions of "SQLite/ja"

From Free Pascal wiki
Jump to navigationJump to search
m (link TDataSet)
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
{{SQLite}}
 
{{SQLite}}
  
{{Infobox databases}}
+
{{Infobox databases/ja}}
  
 
== SQLite と FPC/Lazarus によるサポートについて ==
 
== SQLite と FPC/Lazarus によるサポートについて ==
SQLite is an embedded (non-server) single-user database that can be used in FPC and Lazarus applications. Various drivers can be used to access SQLite from FPC/Lazarus programs.
+
SQLiteは、FPCとLazarusアプリケーションで使用できる組み込み(非サーバー)の単一ユーザーデータベースである。さまざまなドライバーを使用して、FPC/LazarusプログラムからSQLiteにアクセスできる。すべてのドライバーは、動作するために実行可能ディレクトリ(プロジェクトディレクトリまたはLazarusプロジェクト設定に依存する)にSQLiteライブラリ/dllが必要である(および実行可能ファイルと一緒に配布される)
All drivers do need the SQLite library/dll in the executable directory (which can be your project directory or e.g. (projectdir)/lib/architecture/ depending on your Lazarus project settings) (and distributed with your executable) in order to work.
 
  
Win64: please see warning [[Windows Programming Tips#FPC 2.6.x/Lazarus warning|here]] on not using certain FPC/Lazarus Win64 versions.
+
Win64: FPC/Lazarus Win64に関しては、特定のFPC/Lazarus Win64バージョンを使用しないようにすることに関する[[Windows Programming Tips#FPC 2.6.x/Lazarus warning|警告]]がある。
  
 
=== SQLite への直接アクセス ===
 
=== SQLite への直接アクセス ===
You can use an easy way to connect SQLite with Lazarus. Components you are named LiteDAC. SQLite Data Access Components (LiteDAC) is a library of components that provides native connectivity to SQLite from Lazarus (and Free Pascal) on Windows, Mac OS X, iOS, Android, Linux, and FreeBSD for both 32-bit and 64-bit platforms. LiteDAC is designed for programmers to develop truly cross-platform desktop and mobile SQLite database applications with no need to deploy any additional libraries.
+
LiteDAC(SQLite Data Access Components)は、Lazarus(およびFree Pascal)からWindows、Mac OS X、iOS、Android、Linux、FreeBSDの32ビットおよび64ビットプラットフォームに対して、SQLiteへのネイティブ接続を提供するコンポーネントのライブラリである。LiteDACは、プログラマーが追加のライブラリをデプロイすることなく、真にクロスプラットフォームなデスクトップおよびモバイルSQLiteデータベースアプリケーションを開発できるように設計されている。
You can download a trial version of this commercial product at [https://www.devart.com/litedac/download.html Lazarus components].
+
 
 +
商業的な製品のトライアルバージョンを以下でダウンロードできる: [https://www.devart.com/litedac/download.html Lazarus components]
  
 
=== ビルトインの SQLDB ===
 
=== ビルトインの SQLDB ===
FPC/Lazarus offers the built-in SQLDB components that include support for SQLite databases ([[TSQLite3Connection]]) from the [[SQLdb tab]] of the [[Component Palette]], which allow you to e.g. create GUIs with database components such as [[TDBGrid]]s. The advantage of using SQLDB is that it is fairly easy to change to a different database such as Firebird or PostgreSQL without changing your program too much.
+
FPC/Lazarusには、組み込みのSQLDBコンポーネントが含まれており、これにはSQLiteデータベースへのサポート([[TSQLite3Connection/ja]])が含まれている。これは[[Component Palette/ja]][[SQLdb tab/ja]]からアクセスでき、例えば[[TDBGrid/ja]]などのデータベースコンポーネントを使用したGUIを作成することができる。SQLDBを使用する利点は、プログラムをあまり変更することなく、FirebirdやPostgreSQLなどの異なるデータベースに簡単に変更できる。
See below for details.
+
 
 +
詳細は以下を参照のこと
  
==== Spatialite support ====
+
==== Spatialiteサポート ====
Spatialite are GIS extensions to SQLite which you can use from within SQLDB. See [[Spatialite]].
+
Spatialiteは、SQLiteにGIS(地理情報システム)機能を追加したもので、SQLDB内から使用することができる。詳細については、[[Spatialite]]を参照のこと。
  
==== Support for SQLite encryption ====
+
==== SQLiteの暗号化のサポート ====
In recent FPC versions (implemented March 2012), SQLDB included support for some extended versions of SQLite3 which encrypt the SQLite database file using the AES algorithm. Use the password property to set the encryption key.
+
最近のFree Pascal Compiler(FPC)のバージョンでは(2012年3月に実装された)、SQLDBはSQLite3の拡張バージョンのいくつかをサポートしており、これによりSQLiteデータベースファイルをAESアルゴリズムを使用して暗号化することができる。暗号化キーを設定するには、パスワードプロパティを使用する。
  
 
Examples:  
 
Examples:  
* [http://sqlcipher.net/ SQLCipher]: open source, e.g. Windows binaries not for free (you have to compile them yourself)
+
* [http://sqlcipher.net/ SQLCipher]: オープンソース、例えば、Windows用バイナリは無料ではない(自身でコンパイルする必要がある)
* [http://system.data.sqlite.org/ System.Data.SQLite]: open source, Windows (32, 64, CE) binaries available, download e.g one of the Precompiled Binaries and rename SQLite.Interop.dll to sqlite3.dll (if you're using the Statically Linked ones, presumably you need to rename System.Data.SQLite.DLL to sqlite3.dll)
+
* [http://system.data.sqlite.org/ System.Data.SQLite]: オープンソース、Windows (32, 64, CE) バイナリが利用できる。コンパイルされたバイナリの1つをダウンロードし、SQLite.Interop.dllをsqlite3.dllにリネームする(もし静的にリンクしているのであれば、System.Data.SQLite.DLLをsqlite3.dllにリネームする必要がある)
* [http://wxcode.sourceforge.net/docs/wxsqlite3/ wxSQLite3]: open source, some binaries for Linux available (ex: https://launchpad.net/ubuntu/oneiric/+package/libwxsqlite3-2.8-0)
+
* [http://wxcode.sourceforge.net/docs/wxsqlite3/ wxSQLite3]: オープンソース、Linuxに対するいくつかのバイナリが利用できる(例えば: https://launchpad.net/ubuntu/oneiric/+package/libwxsqlite3-2.8-0)
  
 
==== sqlite3backup ====
 
==== sqlite3backup ====
sqlite3backup is a unit provided with FPC (not in Lazarus but can be used programmatically) that provides backup/restore functionality for SQLite3. It uses SQLDB's sqlite3conn.
+
sqlite3backupは、FPCに提供されているユニットであり、Lazarusには含まれていないが、プログラムで使用することができる。これは、SQLite3のバックアップ/リストア機能を提供する。sqlite3backupは、SQLDBのsqlite3connを使用する。
  
 
=== Zeos ===
 
=== Zeos ===
Line 37: Line 38:
 
[http://source.online.free.fr/ SqlitePass] components. Status: unknown.
 
[http://source.online.free.fr/ SqlitePass] components. Status: unknown.
  
=== TSQLite3Dataset and TSQLiteDataset ===
+
=== TSQLite3Dataset TSQLiteDataset ===
There are also separate TSQLiteDataset (unit sqliteds) and TSQLite3Dataset (unit sqlite3ds) packages; see below for a description on how to use them. Visit the [http://sqlite4fpc.yolasite.com/ sqlite4fpc homepage] to find the API reference and more tutorials.
+
TSQLiteDataset(sqlitedsユニット)およびTSQLite3Dataset(sqlite3dsユニット)パッケージも提供されてる。APIリファレンス、チュートリアルに関しては使用法は以下を参照のこと
 
+
[http://sqlite4fpc.yolasite.com/ sqlite4fpc homepage]
TSqliteDataset and TSqlite3Dataset are [[TDataSet]] descendants that access, respectively, 2.8.x and 3.x.x sqlite databases. For new projects, you would presumably use TSQlite3Dataset as SQLite 3.x is the current version.
 
  
Below is a list of the principal advantages and disadvantages compared to other FPC/Lazarus SQLite drivers/access methods:
+
TSQLiteDatasetとTSQLite3Datasetは、それぞれ2.8.xおよび3.x.xのSQLiteデータベースにアクセスする、[[TDataSet]]の派生クラスである。新しいプロジェクトでは、SQLite 3.xが現在のバージョンであるため、TSQLite3Datasetを使用することが一般的である。
  
Advantages:
+
他のFPC/LazarusのSQLiteドライバやアクセス方法と比較した場合の主な利点と欠点は次のとおりである:
* Flexible: programmers can choose to use or not to use the SQL language, allowing them to work with simple table layouts or any complex layout that SQL/sqlite allows
 
Disadvantages:
 
* Changing to other databases is more difficult than if you use the SQLDB or Zeos components
 
  
{{Note|Given the above, many users will use SQLDB or Zeos due to the advantages unless they need lower-level access to the SQLite library}}
+
利点:
 +
* 柔軟性: プログラマーはSQL言語を使用するかどうかを選択できる。これにより、シンプルなテーブルレイアウトやSQL/sqliteで許可されている任意の複雑なレイアウトで作業できる。
 +
欠点:
 +
* 他のデータベースに変更する際、SQLDBやZeosコンポーネントを使用する場合よりも、変更がより困難になる。
 +
{{Note|上記の情報から、多くのユーザーはSQLDBやZeosを利用することが一般的である。これらのツールを利用することで、SQLiteデータベースへの簡単な接続や操作が可能になる。}}
  
== Using the SQLdb components with SQLite ==
+
== SQLiteでSQLdbコンポーネントを使用する ==
These instructions are focused on SQLDB (the TSQLite3Connection) specifics for SQLite. For a general overview, have a look at [[SqlDBHowto|SqlDBHowto]] which has some useful information about the SQLdb components.
+
これらの手順は、特にSQLiteデータベースのSQLDBコンポーネント、特にTSQLite3Connectionの利用に焦点を当てている。SQLDBコンポーネントやそれらの使用方法についてより包括的に理解するには、[[SqlDBHowto|SqlDBHowto/ja]]を参照のこと。これには、LazarusのSQLDBコンポーネントに関する一般的な概要や有用な情報が含まれている。
  
See [[SQLdb_Tutorial1]] for a tutorial on creating a GUI database-enabled program that is written for SQLite/SQLDB (as well as for Firebird/SQLDB, PostgreSQL/SQLDB, basically any RDBMS SQLDB supports).
+
[[SQLdb_Tutorial1/ja]]では、SQLite/SQLDB(およびFirebird/SQLDB、PostgreSQL/SQLDBなど、SQLDBがサポートするほとんどのRDBMS)向けに書かれたGUIデータベース対応プログラムのチュートリアルを見ることができる。
  
We will use a combination of three components from the Lazarus SQLdb tab: TSQLite3Connection, TSQLTransaction and TSQLQuery. The TSQLQuery acts as our TDataset; in the simplest case it just represents one of our tables. For the sake of simplicity: make sure you already have an existing SQLite database file and don't need to create a new one now.
+
LazarusのSQLdbタブから3つのコンポーネントの組み合わせを使用する: TSQLite3Connection、TSQLTransaction、TSQLQueryである。TSQLQueryはTDatasetとして機能し、最も単純な場合にはテーブルの1つを表します。単純化のために、既存のSQLiteデータベースファイルがすでに存在しており、新しいものを作成する必要がないことを確認してください。
TSQLite3Connection can be found in the ''sqlite3conn'' unit, if you want to declare it yourself or are working in FreePascal.
+
TSQLite3Connectionは、自分で宣言したい場合やFreePascalで作業している場合は、''sqlite3conn''ユニットで見つけることができる。
  
The three components are connected with each other as usual: In the TSQLQuery set the properties Database and Transaction, in the TSQLTransaction set the property Database. There is not much to do in the Transaction and Connection components, most of the interesting things will be done in the TSQLQuery. Configure the components as follows:
+
通常通り、これらの3つのコンポーネントは互いに接続される。TSQLQueryでは、DatabaseとTransactionのプロパティを設定する。TSQLTransactionでは、Databaseのプロパティを設定する。TransactionとConnectionのコンポーネントではあまりすることはない。興味深いことのほとんどは、TSQLQueryで行われます。以下のようにコンポーネントを設定する:
  
 
TSQLite3Connection:
 
TSQLite3Connection:
* DatabaseName: Set this property to the file name (absolute path!) of your SQLite file. Unfortunately, you cannot simply use a relative path that works unchanged at designtime and at runtime ***is this still true? Can't you just copy the db file in a post-build shell script or symlink it?***. You should make sure that at application start the correct path to the file is always set programmatically, no matter what it contained at designtime.
+
* DatabaseName: このプロパティをSQLiteファイルのファイル名(絶対パス!)に設定します。残念ながら、単純に相対パスを使用してデザイン時とランタイム時で変更せずに動作する方法はない。***これはまだ真実か?ポストビルドのシェルスクリプトでdbファイルを単にコピーするか、シンボリックリンクを作成できない?***。デザイン時に含まれている内容に関係なく、常に正しいファイルへのパスがアプリケーション起動時にプログラムによって設定されていることを確認する必要がある。
  
Note: To set the full library path (if you place your sqlite dll/so/dylib in a place where the OS won't find it, like the application directory on Linux/OSX), you can set the ''SQLiteLibraryName'' property (BEFORE any connection is established e.g. in the OnCreate event of the main form), like this:
+
注意: フルライブラリパスを設定するには(Linux/OSXのアプリケーションディレクトリなど、OSがそれを見つけられない場所にsqliteのdll/so/dylibを配置した場合)''SQLiteLibraryName''プロパティを設定できます(任意の接続が確立される前に、たとえばメインフォームのOnCreateイベント内で)以下のように:
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
 
SQLiteLibraryName:='./sqlite3.so';
 
SQLiteLibraryName:='./sqlite3.so';
Line 70: Line 71:
  
 
TSQLQuery:
 
TSQLQuery:
* SQL: Set it to some simple select query on one of your tables. For example, if you have a table 'foo' and want this dataset to represent this table then just use the following: <syntaxhighlight lang="SQL">SELECT * FROM foo</syntaxhighlight>
+
* SQL: これをテーブルのいずれかに対するシンプルなselectクエリに設定する。例えば、テーブル 'foo' があり、このデータセットがこのテーブルを表すようにしたい場合は、以下を使用する:
 
+
<syntaxhighlight lang="SQL">SELECT * FROM foo</syntaxhighlight>
* Active: Set this to True from within the IDE to test whether it is all set up correctly. This will also automatically activate the transaction and the connection objects. If you receive an error then either the DatabaseName of the connection is not correct or the SQL query is wrong. Later,  when we are done adding the fields (see below) set them all to inactive again, we don't want the IDE to lock the SQLite database (single user!) when testing the application.
+
* Active: IDE内でこれをTrueに設定して、すべてが正しく設定されているかどうかをテストする。これにより、トランザクションと接続オブジェクトも自動的にアクティブになる。エラーが発生した場合は、接続のDatabaseNameが正しくないか、SQLクエリが間違っている可能性がある。後で、フィールドを追加し終えた後(以下を参照)、すべてを再び非アクティブに設定してください。IDEがアプリケーションのテスト中にSQLiteデータベースをロックしないようにします(シングルユーザーで!)
 
 
* ''Probably not necessary for proper operation - will need to be checked (June 2012)'' Now we can add Fields to our TSQLQuery. While the components are still set to active do a right click and "edit fields...". Click the "+" button and add fields. It will list all fields your SQL query returned. Add every field you will need, you can also add lookup fields here; in this case just make sure you have already defined all needed fields in the other datasets before you start adding lookup fields that refer to them. If your table has many columns and you don't need them all you can just leave them out, you can also make your SQL a bit more specific.
 
 
 
* In your code you need to call SQLQuery.ApplyUpdates and SQLTransaction.Commit, TSQLQuery.AfterPost and AfterInsert events are a good place for this when using it with data aware controls but of course you can also postpone these calls to a later time. If you don't call them, the database will not be updated.
 
 
 
* "Database is locked": The IDE might still be locking the database (SQLite is a single user database), you probably forgot to set the components to inactive and disconnected again after you were done defining all the fields of your TSQLQuery objects. Use the Form's OnCreate event to set the path and activate the objects at runtime only. Most of the things you set in the TSQLQuery from within the IDE don't require (and some don't even allow) them to be active at design time, the only exception is defining the fields where it wants to read the table design, so inactive at design time should be the normal state.
 
  
* Your tables should all have a primary key and you must make sure that the corresponding field has pfInKey and nothing else in its PoviderFlags (these flags control how and where the field is used when automatically constructing the update and delete queries).
+
* ''おそらく正常な動作には必要ないかもしれない - 確認する必要がある(2012年6月)''。これで、TSQLQueryにフィールドを追加できるようになった。コンポーネントがまだアクティブに設定されている間に、右クリックして「edit fields...」をクリックする。"+"ボタンをクリックしてフィールドを追加する。これにより、SQLクエリが返したすべてのフィールドが一覧表示される。必要なすべてのフィールドを追加し、ルックアップフィールドもここで追加できる。この場合、他のデータセットで必要なフィールドをすでに定義していることを確認した後、参照フィールドを追加することを開始すること。テーブルに多くの列がある場合で、すべてを必要としない場合は、それらは省略できる。SQLを少し具体的にすることもできる。
 
+
* コード内でSQLQuery.ApplyUpdatesおよびSQLTransaction.Commitを呼び出す必要がある。データ連動コントロールと一緒に使用する場合は、TSQLQuery.AfterPostおよびAfterInsertイベントが良い場所だが、もちろん、これらの呼び出しを後で行うこともできる。これらの呼び出しを行わない場合、データベースは更新されない。
* If you are using lookup fields
+
* "Database is locked": IDEがまだデータベースをロックしているかもしれない(SQLiteはシングルユーザーデータベースである)。TSQLQueryオブジェクトのすべてのフィールドを定義した後に、コンポーネントを非アクティブにしてから切断するのを忘れた可能性がある。実行時にパスを設定し、オブジェクトをアクティブにするには、フォームのOnCreateイベントを使用する。IDE内でTSQLQueryに設定するほとんどの設定は、デザイン時にアクティブである必要はなく(一部はデザイン時にアクティブであってはいけない場合もある)、唯一の例外はフィールドの定義です。デザイン時に非アクティブであることが通常の状態であるべきである。
** make sure the ProviderFlags for the lookup field is completely empty so it won't attempt to use its name in an update query. The lookup field itself is not a data field, it only acts on the value of another field, the corresponding key field, and only this key field will later be used in the update queries. You can set the key field to hidden because usually you don't want to see it in your DBGrid but it needs to be defined.
+
* テーブルはすべて主キーを持っている必要があり、対応するフィールドがpfInKeyのみであり、他のフラグがないようにする(これらのフラグは、自動的に更新クエリと削除クエリを構築する際にフィールドがどのように使用されるか、およびどこで使用されるかを制御する)。
** LookupCache must be set to True. At the time of this writing for some reason the lookup field will not display anything otherwise (but still work) and strangely the exact opposite is the case when working with the TSQLite3Dataset or other TXXXDataset components, here it must be set to False. I'm not yet sure whether this is intended behavior or a bug.
+
* ルックアップフィールドを用いている場合
 
+
** ルックアップフィールドのProviderFlagsが完全に空であることを確認すること。これにより、更新クエリでその名前が使用されることはない。ルックアップフィールド自体はデータフィールドではなく、他のフィールド、つまり対応するキーフィールドの値にのみ作用し、後で更新クエリで使用されるのはこのキーフィールドのみである。通常、DBGridに表示したくないキーフィールドを非表示にすることができるが、定義する必要がある。
* Usually with simple tables you won't need to set any of the InsertSQL, UpdateSQL and DeleteSQL properties, just leave them empty. If you have the ProviderFlags of all your fields set correctly it should be able to create the needed SQL on the fly. For more details on InsertSQL, UpdateSQL and DeleteSQL, see [[Working_With_TSQLQuery#TSQLQuery.InsertSQL.2C_TSQLQuery.UpdateSQL_and_TSQLQuery.DeleteSQL:_Basic_Use_of_Parameters]].
+
** LookupCacheをTrueに設定する必要がある。現時点では、なぜかルックアップフィールドはそれ以外の場合(しかし動作はする)に何も表示されないため、これを設定する必要がある。そして、奇妙なことに、TSQLite3Datasetや他のTXXXDatasetコンポーネントを使用する場合は正反対の設定にする必要がある。こちらではFalseに設定する必要がある。これが意図された動作なのか、それともバグなのかはまだ確信が持てない。
 
+
* 通常、シンプルなテーブルでは、InsertSQL、UpdateSQL、DeleteSQLのいずれのプロパティも設定する必要はない。これらを空のままにしておいてよい。すべてのフィールドのProviderFlagsが正しく設定されていれば、必要なSQLを動的に作成できるはずである。InsertSQL、UpdateSQL、DeleteSQLの詳細については、[[Working_With_TSQLQuery#TSQLQuery.InsertSQL.2C_TSQLQuery.UpdateSQL_and_TSQLQuery.DeleteSQL:_Basic_Use_of_Parameters]]を参照のこと。
After the above is all set up correctly, you should now be able to use the TSQLQuery like any other TDataset, either by manipulating its data programmatically or by placing a TDatasouce on the Form, connecting it to the TSQLQuery and then using data contols like TDBGrid etc.
+
上記の設定がすべて正しく行われている場合、TSQLQueryを他の任意のTDatasetと同様に使用できるはずである。プログラムでデータを操作するか、フォームにTDatasouceを配置し、それをTSQLQueryに接続してから、TDBGridなどのデータコントロールを使用することができる。
 
+
===データベースを作る===
===Creating a Database===
+
[http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnection.createdb.html TSQLite3Connection.CreateDB]メソッドは親クラスから継承されたもので実際には何も行わない。まだファイルが存在しない場合にデータベースを作成するには、次の例のようにテーブルデータを書き込む必要がある。
The [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnection.createdb.html TSQLite3Connection.CreateDB] method inherited from the parent class actually does nothing; to create a database if no file exists yet, you simply have to write table data as in the following example:
+
(Lazarus 1.3以降で提供されているsqlite_encryption_pragmaの例から抜粋されたコード)
 
 
(Code extracted from sqlite_encryption_pragma example that ships with Lazarus 1.3 onwards)
 
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
 
var
 
var
Line 99: Line 92:
 
begin
 
begin
  
   SQLite3Connection1.Close; // Ensure the connection is closed when we start
+
   SQLite3Connection1.Close; // 開始時はコネクションが閉じていることを保証する
  
 
   try
 
   try
     // Since we're making this database for the first time,
+
     // このデータベースは初めて作られているので
     // check whether the file already exists
+
     // ファイルが既にあるかどうか確かめる
 
     newFile := not FileExists(SQLite3Connection1.DatabaseName);
 
     newFile := not FileExists(SQLite3Connection1.DatabaseName);
  
 
     if newFile then
 
     if newFile then
 
     begin
 
     begin
       // Create the database and the tables
+
       // データベースとテーブルを作る
 
       try
 
       try
 
         SQLite3Connection1.Open;
 
         SQLite3Connection1.Open;
 
         SQLTransaction1.Active := true;
 
         SQLTransaction1.Active := true;
  
         // Here we're setting up a table named "DATA" in the new database
+
         // 「DATA」という名前の新しいデータベースを設定する
 
         SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+
 
         SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+
 
                     ' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+
 
                     ' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+
Line 120: Line 113:
 
                     ' "Info" Char(128) NOT NULL);');
 
                     ' "Info" Char(128) NOT NULL);');
  
         // Creating an index based upon id in the DATA Table
+
         // DATAテーブルのidに基づいてインデクスを作る
 
         SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');
 
         SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');
  
Line 136: Line 129:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Creating user defined collations ===
+
===ユーザー定義の照合順序を作成する ===
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
// utf8 case-sensitive compare callback function
+
// utf8 の大文字小文字を比較するコールバック関数
 
function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
var S1, S2: AnsiString;
 
var S1, S2: AnsiString;
Line 147: Line 140:
 
end;
 
end;
  
// utf8 case-insensitive compare callback function
+
// utf8 の大文字小文字を比較するコールバック関数
 
function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
var S1, S2: AnsiString;
 
var S1, S2: AnsiString;
Line 156: Line 149:
 
end;
 
end;
  
// register collation using SQLite3 API (requires sqlite3dyn unit):
+
// SQLite3 APIを使用して照合順序を登録する(sqlite3dynユニットが必要):
 
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
 
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
// or using method of TSQLite3Connection:
+
// もしくはTSQLite3Connectionのメソッドを使用:
 
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);   
 
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);   
  
// now we can use case-insensitive comparison in SQL like:
+
// ここでSQL様に大文字小文字を区別しない比較を用いることができる:
 
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'
 
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'
  
// but this does not work for LIKE operator
+
// これはLIKE演算子では機能しない
// in order to support also LIKE operator we must overload default LIKE function using sqlite3_create_function()
+
// また、LIKE演算子をサポートするためには、sqlite3_create_function()を用いてデフォルトのLIKEをオーバーロードしなければならない
 
// http://www.sqlite.org/lang_corefunc.html#like
 
// http://www.sqlite.org/lang_corefunc.html#like
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Creating user defined functions ===
+
=== ユーザー定義関数を作る ===
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
// example overloading default LOWER() function with user supplied function
+
// デフォルトの提供されたLOWER()関数をユーザーにオーバーロードする例
// to run this demo, you must add units 'sqlite3dyn' and 'ctypes' to your uses-clause
+
// このデモを実行するにはuses節に 'sqlite3dyn' 'ctypes'を記述する必要がある
// and add a const 'SQLITE_DETERMINISTIC' with value $800
+
// そして、定数'SQLITE_DETERMINISTIC'の値を$800とする
  
 
procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl;
 
procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl;
Line 183: Line 176:
 
end;
 
end;
  
// register function LOWER() using SQLite3 API (requires sqlite3dyn unit):
+
// SQLite3 APIを用いてLOWER()関数を登録する(sqlite3dynユニットが必要である):
 
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);
 
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== SQLite3 and Dates ===
+
=== SQLite3 と 日付 ===
* SQLite 3 doesn't store dates as a special DateTime value. It can stores them as strings, doubles or integers - see http://www.sqlite.org/datatype3.html#datetime.
+
* SQLite 3では、日付を特別なDateTime値として保存しない。代わりに、それらを文字列、倍精度浮動小数点数、または整数として保存できる。詳細については http://www.sqlite.org/datatype3.html#datetimeを参照のこと
* In strings, the  date separator is '-' as per SQL standard/ISO 8601. Thus, if you do an INSERT using the built-in DATE function, it will store it as something like 'YYYY-MM-DD'.
+
* 文字列では、日付の区切り記号はSQL標準/ISO 8601に従って '-' である。したがって、組み込みのDATE関数を使用してINSERTを行うと、'YYYY-MM-DD'のような形式で保存される。
* Reading a DateTime value can cause problems for DataSets if they are stored as strings: the .AsDateTime qualifier can stall on an SQLite 'string date' but this can be overcome by using something like <tt>strftime(''%d/%m/%Y'',recdate) AS sqlite3recdate</tt> in your SQL SELECT statement, which forces SQLite3 to return the date record in a specified format. (the format string %d/%m/%d corresponds to your locale date format which .AsDateTime will understand) '''==> Please open a bug report with an example application demonstrating the problemif this is the case'''
+
* DateTime値を文字列として保存すると、DataSetsで問題が発生する可能性がある。.AsDateTime修飾子はSQLiteの「文字列日付」でスタックする可能性があるが、SQL SELECTステートメントで<tt>strftime(''%d/%m/%Y'',recdate) AS sqlite3recdate</tt>のようなものを使用することで、SQLite3に指定された形式で日付レコードを返すように指示できる(フォーマット文字列%d /%m /%dは、.AsDateTimeが理解するロケール日付形式に対応しています)'''==> このような場合は、問題を示す例のアプリケーションを使用してバグレポートを作成してほしい'''
* When comparing dates stored as strings (using for example the BETWEEN function) remember that the comparison will always be a <b>string</b> comparison, and will therefore depend on how you have stored the date value.
+
日付を文字列として保存している場合(たとえばBETWEEN関数を使用して)、比較は常に'''文字列'''の比較になることを覚えておくこと。したがって、比較結果は日付値の保存方法に依存する。
==== Default values in local time instead of UTC ====
+
==== UTCの代わりにローカルタイムをデフォルトに用いる ====
CURRENT_TIME, CURRENT_DATE and CURRENT_TIMESTAMP return current UTC date and/or time. For local date and/or times we can use:
+
CURRENT_TIME, CURRENT_DATE and CURRENT_TIMESTAMP は現在のUTC日付および、もしくは時刻を返す。ローカルの日付、および、または時刻を用いるために以下のようにする:
 
   DEFAULT (datetime('now','localtime')) for datetime values formated YYYY-MM-DD HH:MM:SS
 
   DEFAULT (datetime('now','localtime')) for datetime values formated YYYY-MM-DD HH:MM:SS
 
   DEFAULT (date('now','localtime')) for date value formated YYYY-MM-DD
 
   DEFAULT (date('now','localtime')) for date value formated YYYY-MM-DD
 
   DEFAULT (time('now','localtime')) for time value formated HH:MM:SS
 
   DEFAULT (time('now','localtime')) for time value formated HH:MM:SS
  
===SQLDB And SQLite troubleshooting===
+
===SQLDB SQLite のトラブルシューティング===
* Keep in mind that for designtime support to work (fields etc) Lazarus must find sqlite3.dll too.
+
* デザイン時のサポート(フィールドなど)が機能するには、Lazarusがsqlite3.dllも見つける必要があることに注意すること。
* The same goes for the database filename. Always use absolute path if you use components to extract e.g. fieldnames at designtime. Otherwise the IDE will create an empty file in its directory. In case of trouble, check if the lazarus/ directory doesn't hold a zero byte copy of the database file.
+
* 同じことがデータベースのファイル名にも適用される。デザイン時にフィールド名などを抽出する場合は常に絶対パスを使用すること。そうしないと、IDEがそのディレクトリに空のファイルを作成する。問題が発生した場合は、lazarus/ディレクトリにデータベースファイルのゼロバイトコピーがないか確認すること。
* If you have master/detail relationship, you need to refresh master dataset after each insert, in order to get value for slave dataset foreign key field. You can do that in AfterPost event of the master dataset, by calling one of the following overloaded procedures:
+
* マスター/ディテール関係がある場合、スレーブデータセットの外部キーの値を取得するために、各挿入後にマスターデータセットを更新する必要がある。これは、マスターデータセットのAfterPostイベントで、次のオーバーロードされた手順のいずれかを呼び出すことで行うことができる:
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
 
interface
 
interface
Line 210: Line 203:
 
   
 
   
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);
//This procedure refreshes a dataset and positions cursor to last record
+
 
//To be used if Dataset is not guaranteed to be sorted by an autoincrement primary key
+
//このプロシージャはデータセットをリフレッシュし、カーソルを最後のレコードに配置する
 +
//データセットが自動インクリメントの主キーでソートされていることが保証されていない場合に使用する必要がある
 
var
 
var
 
   vLastID: Integer;
 
   vLastID: Integer;
Line 217: Line 211:
 
begin
 
begin
 
   vUpdateStatus := pDataset.UpdateStatus;
 
   vUpdateStatus := pDataset.UpdateStatus;
   //Get last inserted ID in the database
+
   //データベースに最後に挿入されたIDを取得
 
   pDataset.ApplyUpdates;
 
   pDataset.ApplyUpdates;
 
   vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
 
   vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
   //Now come back to respective row
+
   //ここで、それぞれの行に戻る
 
   if vUpdateStatus = usInserted then begin
 
   if vUpdateStatus = usInserted then begin
 
     pDataset.Refresh;
 
     pDataset.Refresh;
     //Refresh and go back to respective row
+
     //それぞれの行に戻り、リフレッシュする
 
     pDataset.Locate(pKeyField,vLastID,[]);
 
     pDataset.Locate(pKeyField,vLastID,[]);
 
   end;
 
   end;
Line 229: Line 223:
 
   
 
   
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);
//This procedure refreshes a dataset and positions cursor to last record
+
//このプロシージャはデータセットをリフレッシュし、カーソルを最後のレコードに配置する
//To be used only if DataSet is guaranteed to be sorted by an autoincrement primary key
+
//データセットが自動インクリメントの主キーでソートされていることが保証されていない場合に使用する必要がある
 
var
 
var
 
   vLastID: Integer;
 
   vLastID: Integer;
Line 240: Line 234:
 
   if vUpdateStatus = usInserted then begin
 
   if vUpdateStatus = usInserted then begin
 
     pDataset.Refresh;
 
     pDataset.Refresh;
     //Dangerous!
+
     //危険!
 
     pDataSet.Last;
 
     pDataSet.Last;
 
   end;
 
   end;
Line 247: Line 241:
 
procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
 
procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
 
begin
 
begin
   RefreshADatasetAfterInsert(Dataset as TSQLQuery); //If your dataset is sorted by primary key
+
   RefreshADatasetAfterInsert(Dataset as TSQLQuery); //もしデータセットがプライマリキーでソートされているなら
 
end;   
 
end;   
  
 
procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
 
procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
 
begin
 
begin
   RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //if you are not sure that the dataset is always sorted by primary key
+
   RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //もしデータセットがプライマリキーでソートされていることが不確かなら
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Vacuum and other operations that must be done outside a transaction ===
+
=== トランザクションとは別に行われるべきVacuum と 他のオペレーション ===
 
+
SQLDBは常に接続を必要とするようだが、PragmaやVacuumなどの一部の操作はトランザクションの外で行う必要がある。トランザクションを終了し、必要な操作を実行し、再びトランザクションを開始するトリックを使用する(これにより、SQLDBが混乱しないようする)
SQLDB seems to always require a connection, but some operations like Pragma and Vacuum must
 
be done outside a transaction. The trick is to end transaction, execute what you must and start
 
transaction again (so that sqldb doesn't get confused:)
 
 
 
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
   // commit any pending operations or use a "fresh" sqlconnection
+
   // ペンディング中のすべてのオペレーションをコミットするか、"fresh" sqlconnectionをもちいる
   Conn.ExecuteDirect('End Transaction');  // End the transaction started by SQLdb
+
   Conn.ExecuteDirect('End Transaction');  // SQLdbによって開始されたトランザクションを終える
 
   Conn.ExecuteDirect('Vacuum');
 
   Conn.ExecuteDirect('Vacuum');
   Conn.ExecuteDirect('Begin Transaction'); //Start a transaction for SQLdb to use
+
   Conn.ExecuteDirect('Begin Transaction'); //SQLdbが用いるためトランザクションを開始
 
</syntaxhighlight>
 
</syntaxhighlight>
  

Latest revision as of 14:39, 26 March 2024

English (en) español (es) français (fr) 日本語 (ja) polski (pl) русский (ru) 中文(中国大陆)‎ (zh_CN)

データベースのポータル

参照:

チュートリアル/練習となる記事:

各種データベース

Advantage - MySQL - MSSQL - Postgres - Interbase - Firebird - Oracle - ODBC - Paradox - SQLite - dBASE - MS Access - Zeos

SQLite と FPC/Lazarus によるサポートについて

SQLiteは、FPCとLazarusアプリケーションで使用できる組み込み(非サーバー)の単一ユーザーデータベースである。さまざまなドライバーを使用して、FPC/LazarusプログラムからSQLiteにアクセスできる。すべてのドライバーは、動作するために実行可能ディレクトリ(プロジェクトディレクトリまたはLazarusプロジェクト設定に依存する)にSQLiteライブラリ/dllが必要である(および実行可能ファイルと一緒に配布される)。

Win64: FPC/Lazarus Win64に関しては、特定のFPC/Lazarus Win64バージョンを使用しないようにすることに関する警告がある。

SQLite への直接アクセス

LiteDAC(SQLite Data Access Components)は、Lazarus(およびFree Pascal)からWindows、Mac OS X、iOS、Android、Linux、FreeBSDの32ビットおよび64ビットプラットフォームに対して、SQLiteへのネイティブ接続を提供するコンポーネントのライブラリである。LiteDACは、プログラマーが追加のライブラリをデプロイすることなく、真にクロスプラットフォームなデスクトップおよびモバイルSQLiteデータベースアプリケーションを開発できるように設計されている。

商業的な製品のトライアルバージョンを以下でダウンロードできる: Lazarus components

ビルトインの SQLDB

FPC/Lazarusには、組み込みのSQLDBコンポーネントが含まれており、これにはSQLiteデータベースへのサポート(TSQLite3Connection/ja)が含まれている。これはComponent Palette/jaSQLdb tab/jaからアクセスでき、例えばTDBGrid/jaなどのデータベースコンポーネントを使用したGUIを作成することができる。SQLDBを使用する利点は、プログラムをあまり変更することなく、FirebirdやPostgreSQLなどの異なるデータベースに簡単に変更できる。

詳細は以下を参照のこと

Spatialiteサポート

Spatialiteは、SQLiteにGIS(地理情報システム)機能を追加したもので、SQLDB内から使用することができる。詳細については、Spatialiteを参照のこと。

SQLiteの暗号化のサポート

最近のFree Pascal Compiler(FPC)のバージョンでは(2012年3月に実装された)、SQLDBはSQLite3の拡張バージョンのいくつかをサポートしており、これによりSQLiteデータベースファイルをAESアルゴリズムを使用して暗号化することができる。暗号化キーを設定するには、パスワードプロパティを使用する。

Examples:

  • SQLCipher: オープンソース、例えば、Windows用バイナリは無料ではない(自身でコンパイルする必要がある)
  • System.Data.SQLite: オープンソース、Windows (32, 64, CE) バイナリが利用できる。コンパイルされたバイナリの1つをダウンロードし、SQLite.Interop.dllをsqlite3.dllにリネームする(もし静的にリンクしているのであれば、System.Data.SQLite.DLLをsqlite3.dllにリネームする必要がある)
  • wxSQLite3: オープンソース、Linuxに対するいくつかのバイナリが利用できる(例えば: https://launchpad.net/ubuntu/oneiric/+package/libwxsqlite3-2.8-0)

sqlite3backup

sqlite3backupは、FPCに提供されているユニットであり、Lazarusには含まれていないが、プログラムで使用することができる。これは、SQLite3のバックアップ/リストア機能を提供する。sqlite3backupは、SQLDBのsqlite3connを使用する。

Zeos

Zeos

SQLitePass

SqlitePass components. Status: unknown.

TSQLite3Dataset と TSQLiteDataset

TSQLiteDataset(sqlitedsユニット)およびTSQLite3Dataset(sqlite3dsユニット)パッケージも提供されてる。APIリファレンス、チュートリアルに関しては使用法は以下を参照のこと sqlite4fpc homepage

TSQLiteDatasetとTSQLite3Datasetは、それぞれ2.8.xおよび3.x.xのSQLiteデータベースにアクセスする、TDataSetの派生クラスである。新しいプロジェクトでは、SQLite 3.xが現在のバージョンであるため、TSQLite3Datasetを使用することが一般的である。

他のFPC/LazarusのSQLiteドライバやアクセス方法と比較した場合の主な利点と欠点は次のとおりである:

利点:

  • 柔軟性: プログラマーはSQL言語を使用するかどうかを選択できる。これにより、シンプルなテーブルレイアウトやSQL/sqliteで許可されている任意の複雑なレイアウトで作業できる。

欠点:

  • 他のデータベースに変更する際、SQLDBやZeosコンポーネントを使用する場合よりも、変更がより困難になる。
Light bulb  Note: 上記の情報から、多くのユーザーはSQLDBやZeosを利用することが一般的である。これらのツールを利用することで、SQLiteデータベースへの簡単な接続や操作が可能になる。

SQLiteでSQLdbコンポーネントを使用する

これらの手順は、特にSQLiteデータベースのSQLDBコンポーネント、特にTSQLite3Connectionの利用に焦点を当てている。SQLDBコンポーネントやそれらの使用方法についてより包括的に理解するには、SqlDBHowto/jaを参照のこと。これには、LazarusのSQLDBコンポーネントに関する一般的な概要や有用な情報が含まれている。

SQLdb_Tutorial1/jaでは、SQLite/SQLDB(およびFirebird/SQLDB、PostgreSQL/SQLDBなど、SQLDBがサポートするほとんどのRDBMS)向けに書かれたGUIデータベース対応プログラムのチュートリアルを見ることができる。

LazarusのSQLdbタブから3つのコンポーネントの組み合わせを使用する: TSQLite3Connection、TSQLTransaction、TSQLQueryである。TSQLQueryはTDatasetとして機能し、最も単純な場合にはテーブルの1つを表します。単純化のために、既存のSQLiteデータベースファイルがすでに存在しており、新しいものを作成する必要がないことを確認してください。 TSQLite3Connectionは、自分で宣言したい場合やFreePascalで作業している場合は、sqlite3connユニットで見つけることができる。

通常通り、これらの3つのコンポーネントは互いに接続される。TSQLQueryでは、DatabaseとTransactionのプロパティを設定する。TSQLTransactionでは、Databaseのプロパティを設定する。TransactionとConnectionのコンポーネントではあまりすることはない。興味深いことのほとんどは、TSQLQueryで行われます。以下のようにコンポーネントを設定する:

TSQLite3Connection:

  • DatabaseName: このプロパティをSQLiteファイルのファイル名(絶対パス!)に設定します。残念ながら、単純に相対パスを使用してデザイン時とランタイム時で変更せずに動作する方法はない。***これはまだ真実か?ポストビルドのシェルスクリプトでdbファイルを単にコピーするか、シンボリックリンクを作成できない?***。デザイン時に含まれている内容に関係なく、常に正しいファイルへのパスがアプリケーション起動時にプログラムによって設定されていることを確認する必要がある。

注意: フルライブラリパスを設定するには(Linux/OSXのアプリケーションディレクトリなど、OSがそれを見つけられない場所にsqliteのdll/so/dylibを配置した場合)、SQLiteLibraryNameプロパティを設定できます(任意の接続が確立される前に、たとえばメインフォームのOnCreateイベント内で)以下のように:

SQLiteLibraryName:='./sqlite3.so';

TSQLQuery:

  • SQL: これをテーブルのいずれかに対するシンプルなselectクエリに設定する。例えば、テーブル 'foo' があり、このデータセットがこのテーブルを表すようにしたい場合は、以下を使用する:
SELECT * FROM foo
  • Active: IDE内でこれをTrueに設定して、すべてが正しく設定されているかどうかをテストする。これにより、トランザクションと接続オブジェクトも自動的にアクティブになる。エラーが発生した場合は、接続のDatabaseNameが正しくないか、SQLクエリが間違っている可能性がある。後で、フィールドを追加し終えた後(以下を参照)、すべてを再び非アクティブに設定してください。IDEがアプリケーションのテスト中にSQLiteデータベースをロックしないようにします(シングルユーザーで!)。
  • おそらく正常な動作には必要ないかもしれない - 確認する必要がある(2012年6月)。これで、TSQLQueryにフィールドを追加できるようになった。コンポーネントがまだアクティブに設定されている間に、右クリックして「edit fields...」をクリックする。"+"ボタンをクリックしてフィールドを追加する。これにより、SQLクエリが返したすべてのフィールドが一覧表示される。必要なすべてのフィールドを追加し、ルックアップフィールドもここで追加できる。この場合、他のデータセットで必要なフィールドをすでに定義していることを確認した後、参照フィールドを追加することを開始すること。テーブルに多くの列がある場合で、すべてを必要としない場合は、それらは省略できる。SQLを少し具体的にすることもできる。
  • コード内でSQLQuery.ApplyUpdatesおよびSQLTransaction.Commitを呼び出す必要がある。データ連動コントロールと一緒に使用する場合は、TSQLQuery.AfterPostおよびAfterInsertイベントが良い場所だが、もちろん、これらの呼び出しを後で行うこともできる。これらの呼び出しを行わない場合、データベースは更新されない。
  • "Database is locked": IDEがまだデータベースをロックしているかもしれない(SQLiteはシングルユーザーデータベースである)。TSQLQueryオブジェクトのすべてのフィールドを定義した後に、コンポーネントを非アクティブにしてから切断するのを忘れた可能性がある。実行時にパスを設定し、オブジェクトをアクティブにするには、フォームのOnCreateイベントを使用する。IDE内でTSQLQueryに設定するほとんどの設定は、デザイン時にアクティブである必要はなく(一部はデザイン時にアクティブであってはいけない場合もある)、唯一の例外はフィールドの定義です。デザイン時に非アクティブであることが通常の状態であるべきである。
  • テーブルはすべて主キーを持っている必要があり、対応するフィールドがpfInKeyのみであり、他のフラグがないようにする(これらのフラグは、自動的に更新クエリと削除クエリを構築する際にフィールドがどのように使用されるか、およびどこで使用されるかを制御する)。
  • ルックアップフィールドを用いている場合
    • ルックアップフィールドのProviderFlagsが完全に空であることを確認すること。これにより、更新クエリでその名前が使用されることはない。ルックアップフィールド自体はデータフィールドではなく、他のフィールド、つまり対応するキーフィールドの値にのみ作用し、後で更新クエリで使用されるのはこのキーフィールドのみである。通常、DBGridに表示したくないキーフィールドを非表示にすることができるが、定義する必要がある。
    • LookupCacheをTrueに設定する必要がある。現時点では、なぜかルックアップフィールドはそれ以外の場合(しかし動作はする)に何も表示されないため、これを設定する必要がある。そして、奇妙なことに、TSQLite3Datasetや他のTXXXDatasetコンポーネントを使用する場合は正反対の設定にする必要がある。こちらではFalseに設定する必要がある。これが意図された動作なのか、それともバグなのかはまだ確信が持てない。
  • 通常、シンプルなテーブルでは、InsertSQL、UpdateSQL、DeleteSQLのいずれのプロパティも設定する必要はない。これらを空のままにしておいてよい。すべてのフィールドのProviderFlagsが正しく設定されていれば、必要なSQLを動的に作成できるはずである。InsertSQL、UpdateSQL、DeleteSQLの詳細については、Working_With_TSQLQuery#TSQLQuery.InsertSQL.2C_TSQLQuery.UpdateSQL_and_TSQLQuery.DeleteSQL:_Basic_Use_of_Parametersを参照のこと。

上記の設定がすべて正しく行われている場合、TSQLQueryを他の任意のTDatasetと同様に使用できるはずである。プログラムでデータを操作するか、フォームにTDatasouceを配置し、それをTSQLQueryに接続してから、TDBGridなどのデータコントロールを使用することができる。

データベースを作る

TSQLite3Connection.CreateDBメソッドは親クラスから継承されたもので実際には何も行わない。まだファイルが存在しない場合にデータベースを作成するには、次の例のようにテーブルデータを書き込む必要がある。 (Lazarus 1.3以降で提供されているsqlite_encryption_pragmaの例から抜粋されたコード)

var
  newFile : Boolean;
begin

  SQLite3Connection1.Close; // 開始時はコネクションが閉じていることを保証する

  try
    // このデータベースは初めて作られているので
    // ファイルが既にあるかどうか確かめる
    newFile := not FileExists(SQLite3Connection1.DatabaseName);

    if newFile then
    begin
      // データベースとテーブルを作る
      try
        SQLite3Connection1.Open;
        SQLTransaction1.Active := true;

        // 「DATA」という名前の新しいデータベースを設定する
        SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+
                    ' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+
                    ' "Current_Time" DateTime NOT NULL,'+
                    ' "User_Name" Char(128) NOT NULL,'+
                    ' "Info" Char(128) NOT NULL);');

        // DATAテーブルのidに基づいてインデクスを作る
        SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');

        SQLTransaction1.Commit;

        ShowMessage('Succesfully created database.');
      except
        ShowMessage('Unable to Create new Database');
      end;
    end;
  except
    ShowMessage('Unable to check if database file exists');
  end;
 end;

ユーザー定義の照合順序を作成する

// utf8 の大文字小文字を比較するコールバック関数
function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
var S1, S2: AnsiString;
begin
  SetString(S1, data1, len1);
  SetString(S2, data2, len2);
  Result := UnicodeCompareStr(UTF8Decode(S1), UTF8Decode(S2));
end;

// utf8 の大文字小文字を比較するコールバック関数
function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
var S1, S2: AnsiString;
begin
  SetString(S1, data1, len1);
  SetString(S2, data2, len2);
  Result := UnicodeCompareText(UTF8Decode(S1), UTF8Decode(S2));
end;

// SQLite3 APIを使用して照合順序を登録する(sqlite3dynユニットが必要):
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
// もしくはTSQLite3Connectionのメソッドを使用:
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);  

// ここでSQL様に大文字小文字を区別しない比較を用いることができる:
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'

// これはLIKE演算子では機能しない
// また、LIKE演算子をサポートするためには、sqlite3_create_function()を用いてデフォルトのLIKEをオーバーロードしなければならない
// http://www.sqlite.org/lang_corefunc.html#like

ユーザー定義関数を作る

// デフォルトの提供されたLOWER()関数をユーザーにオーバーロードする例
// このデモを実行するにはuses節に 'sqlite3dyn' と 'ctypes'を記述する必要がある
// そして、定数'SQLITE_DETERMINISTIC'の値を$800とする

procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl;
var S: AnsiString;
begin
  SetString(S, sqlite3_value_text(V[0]), sqlite3_value_bytes(V[0]));
  S := UTF8Encode(AnsiLowerCase(UTF8Decode(S)));
  sqlite3_result_text(ctx, PAnsiChar(S), Length(S), sqlite3_destructor_type(SQLITE_TRANSIENT));
end;

// SQLite3 APIを用いてLOWER()関数を登録する(sqlite3dynユニットが必要である):
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);

SQLite3 と 日付

  • SQLite 3では、日付を特別なDateTime値として保存しない。代わりに、それらを文字列、倍精度浮動小数点数、または整数として保存できる。詳細については http://www.sqlite.org/datatype3.html#datetimeを参照のこと
  • 文字列では、日付の区切り記号はSQL標準/ISO 8601に従って '-' である。したがって、組み込みのDATE関数を使用してINSERTを行うと、'YYYY-MM-DD'のような形式で保存される。
  • DateTime値を文字列として保存すると、DataSetsで問題が発生する可能性がある。.AsDateTime修飾子はSQLiteの「文字列日付」でスタックする可能性があるが、SQL SELECTステートメントでstrftime(%d/%m/%Y,recdate) AS sqlite3recdateのようなものを使用することで、SQLite3に指定された形式で日付レコードを返すように指示できる(フォーマット文字列%d /%m /%dは、.AsDateTimeが理解するロケール日付形式に対応しています)。==> このような場合は、問題を示す例のアプリケーションを使用してバグレポートを作成してほしい

日付を文字列として保存している場合(たとえばBETWEEN関数を使用して)、比較は常に文字列の比較になることを覚えておくこと。したがって、比較結果は日付値の保存方法に依存する。

UTCの代わりにローカルタイムをデフォルトに用いる

CURRENT_TIME, CURRENT_DATE and CURRENT_TIMESTAMP は現在のUTC日付および、もしくは時刻を返す。ローカルの日付、および、または時刻を用いるために以下のようにする:

 DEFAULT (datetime('now','localtime')) for datetime values formated YYYY-MM-DD HH:MM:SS
 DEFAULT (date('now','localtime')) for date value formated YYYY-MM-DD
 DEFAULT (time('now','localtime')) for time value formated HH:MM:SS

SQLDB と SQLite のトラブルシューティング

  • デザイン時のサポート(フィールドなど)が機能するには、Lazarusがsqlite3.dllも見つける必要があることに注意すること。
  • 同じことがデータベースのファイル名にも適用される。デザイン時にフィールド名などを抽出する場合は常に絶対パスを使用すること。そうしないと、IDEがそのディレクトリに空のファイルを作成する。問題が発生した場合は、lazarus/ディレクトリにデータベースファイルのゼロバイトコピーがないか確認すること。
  • マスター/ディテール関係がある場合、スレーブデータセットの外部キーの値を取得するために、各挿入後にマスターデータセットを更新する必要がある。これは、マスターデータセットのAfterPostイベントで、次のオーバーロードされた手順のいずれかを呼び出すことで行うことができる:
interface
    procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);overload;
    procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);overload;  
 
implementation
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);

//このプロシージャはデータセットをリフレッシュし、カーソルを最後のレコードに配置する
//データセットが自動インクリメントの主キーでソートされていることが保証されていない場合に使用する必要がある
var
  vLastID: Integer;
  vUpdateStatus : TUpdateStatus;
begin
  vUpdateStatus := pDataset.UpdateStatus;
  //データベースに最後に挿入されたIDを取得
  pDataset.ApplyUpdates;
  vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
  //ここで、それぞれの行に戻る
  if vUpdateStatus = usInserted then begin
    pDataset.Refresh;
    //それぞれの行に戻り、リフレッシュする
    pDataset.Locate(pKeyField,vLastID,[]);
  end;
end;
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);
//このプロシージャはデータセットをリフレッシュし、カーソルを最後のレコードに配置する
//データセットが自動インクリメントの主キーでソートされていることが保証されていない場合に使用する必要がある
var
  vLastID: Integer;
  vUpdateStatus : TUpdateStatus;
begin
  vUpdateStatus := pDataset.UpdateStatus;
  pDataset.ApplyUpdates;
  vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
  if vUpdateStatus = usInserted then begin
    pDataset.Refresh;
    //危険!
    pDataSet.Last;
  end;
end;

procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
begin
  RefreshADatasetAfterInsert(Dataset as TSQLQuery); //もしデータセットがプライマリキーでソートされているなら
end;  

procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
begin
  RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //もしデータセットがプライマリキーでソートされていることが不確かなら
end;

トランザクションとは別に行われるべきVacuum と 他のオペレーション

SQLDBは常に接続を必要とするようだが、PragmaやVacuumなどの一部の操作はトランザクションの外で行う必要がある。トランザクションを終了し、必要な操作を実行し、再びトランザクションを開始するトリックを使用する(これにより、SQLDBが混乱しないようする)。

  // ペンディング中のすべてのオペレーションをコミットするか、"fresh" sqlconnectionをもちいる
  Conn.ExecuteDirect('End Transaction');  // SQLdbによって開始されたトランザクションを終える
  Conn.ExecuteDirect('Vacuum');
  Conn.ExecuteDirect('Begin Transaction'); //SQLdbが用いるためトランザクションを開始

TSQLite3Dataset を使う

この節では、SQLite データベースへアクセスするために、どのように TSQLite2Dataset または TSQLite3Dataset コンポーネント を用いるかを詳しく説明しています。 Luiz Américo による luizmed(at)oi(dot)com(dot)br

要求事項

  • sqlite2 データベースのためには(レガシー):
    • FPC 2.0.0 以上
    • Lazarus 0.9.10 以上
    • SQLite runtime library 2.8.15 以上*
  • Sqlite2 はもはやメインテナンスされておらず、sqlite のサイトでバイナリファイルを見つけることはできません。
  • sqlite3 データベースのためには:
    • FPC 2.0.2 以上
    • Lazarus 0.9.11 (svn revision 8443) 以上
    • SQLite runtime library 3.2.1 以上 (www.sqlite.org から入手してください。)

Lazarus のプロジェクトを作る前に、次の事を確認してください。:

  • SQLite ライブラリが
    • システム PATH にある
    • 実行ファイルの出力されるディレクトリと Lazarus(または現在のプロジェクトの)ディレクトリにある - このオプションは Windows のみです。
  • Linuxでは、cmemを メインプログラムの uses の最初のユニットにしているかどうか
    • Debian や Ubuntu またその他の Debian-like ディストロにおいては、Lazarus IDE に libsqlite-dev/libsqlite3-dev, not only sqlite/sqlite3 パッケージをインストールする必要があります。(OpenSuSe にも適用してください。)

使い方 (基本)

/components/sqlite にあるパッケージをインストールしてください。(ここにその方法があります。)

設計時に下記のプロパティをセットして下さい。

  • FileName: sqliteファイルへのパス[必須]
  • TableName: sql文で使うテーブル名[必須]
  • SQL: SQLのSELECT文 [必要に応じて]
  • SaveOnClose: デフォルト値はfalse。つまり変更は保存されない。trueに変更可能。 [必要に応じて]
  • Active: 設計時またはプログラムのスタート時に設定[必須]

テーブルを作成する(Dataset)

コンポーネントアイコンをダブルクックするか、右マウスボタンのクリックで現れるポップアップメニューより、'Create Table' を選択します。 簡単な説明のあるテーブルエディタが表示されます。

下記は TSqliteDataset と TSqlite3Dataset でサポートされているすべてのフィールドの型です。

  • Integer
  • AutoInc
  • String
  • Memo
  • Bool
  • Float
  • Word
  • DateTime
  • Date
  • Time
  • LargeInt
  • Currency

データを取得する

テーブルを生成した後か、以前作ったテーブルで作業する場合、Open 手続きでデータセットを開いて下さい。 SQL プロパティがセットされていない場合、すべてのフィールドのすべてのレコードを取得するためには、次のような1文をSQLにセットします。:

SQL := 'Select * from TABLENAME';

データファイル上に変更を適用する

ApplyUpdates 関数を使うために, データセットは、主キーの条件を満たす少なくとも1つのフィールドを持っていなければなりません。(値は、UNIQUE であり、NULL ではない必要があります。)

変更を適用するために2つの方法があります。

  • PrimaryKey プロパティに主キーになっているフィールド名を設定する。
  • AutoIncフィールドを加える。(これは TSqliteDataset が自動的にそれを主キーとしてみなすので、より簡単です。)

2つの条件のうち1つをセットしたら、以下を呼び出してください。

ApplyUpdates;
Light bulb  Note: もし、両方の条件がセットされたら、主キーに相当するフィールドが更新の適用に使われます。
Light bulb  Note: 主キーではないフィールドを主キーに設定することは、ApplyUpdate がコールされたときにデータのロスを引き起こします。ですから、選択されたフィールドは、 Null でなく Unique であることを、それを使う前に確認してください。
Master/detail のサンプル

master/detail 関係の様々なサンプル (例えば、顧客と注文の間の関係):

注意事項

  • 10000レコードまではテストして、上手く動きますが、TSqliteDataset はすべてのデータをメモリ上に置くため、必要なデータのみ受け取るようにしてください。(特にMemoフィールドなどに注意).
  • 同じデータファイルに(同じファイル名のプロパティに)、いくつかのテーブル、データセットを持たせることができます。
  • いくつかのデータセット(違うフィールドの組み合わせの)を同じテーブルから作ることができます。
  • SQL文 で WHERE を使ってデータをフィルタすることが可能です。また、データセットのクローズおよび再オープン(あるいは、RefechData メソッドを呼ぶこと)ができます。しかし、この場合、並び順やフィールドの数は同じでなくてはなりません。
  • 複数のテーブルから aliases や join , views などを使って複雑な SQL 文が実行可能です(これらは同じデータファイルにある必要があることに注意)。しかしこの場合、ApplyUpdate は動作しません。もし複雑なクエリをつかって、データファイルに更新を加えたければ私(Luiz Américo)にメールしてください。そうすれば、どういうふうにおこなうか、ヒントをお伝えすることができます。
  • TSqliteDataset で生成されていない sqlite のデータファイルにファイル名を設定するときおよび、そのファイルを開くとき、一部のフィールドが正しい型を検出することが、許可されていません。これらは、string フィールドとして扱われます。

一般的なサンプルが、SVNディレクトリの fpc/fcl-db/src/sqlite にあります。

関連情報