Sign in Join
Wiki copytemporary

SqlDBHowto/ja: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-このテキストは「how-to」として作られている。数多くの質問に1つ、1つ答え、どのように様々なクラスを用いるのか説明したい。これらすべての質問は次から次へと沸き起こり、ある種のチュートリアルとなった。
1+---
2+[[Portal:Databases/ja|**データベースのポータル**]]
3+参照: · [[Databases/ja|Databases 概要]] · [[Database libraries/ja|ライブラリ]] · [[Database field type/ja|フィールドの型]] · [[Data Controls tab/ja|コントロール]] · [[Lazarus DB Faq/ja|FAQ]] · SqlDBHowto/ja · [[Working With TSQLQuery/ja|TSQLQuery の利用]] · [[How to write in-memory database applications in Lazarus/FPC/ja|メモリ上で動作するデータベースの作り方]] · チュートリアル/練習となる記事: · [[Lazarus Database Overview/ja|概要]] · [[SQLdb Tutorial0/ja|0 - データベースのセットアップ]] · [[SQLdb Tutorial1/ja|1 - 開始]] · [[SQLdb Tutorial2/ja|2 - 編集]] · [[SQLdb Tutorial3/ja|3 - クエリ]] · [[SQLdb Tutorial4/ja|4 - データモジュール]] · [[SQLdb Programming Reference/ja]] · 各種データベース · [[Advantage Database Server/ja|Advantage]] \- [[MySQLDatabases/ja|MySQL]] \- [[mssqlconn/ja|MSSQL]] \- [[postgres/ja|Postgres]] \- [[Firebird/ja|Interbase]] \- [[Firebird/ja|Firebird]] \- [[Oracle/ja|Oracle]] \- [[ODBCConn/ja|ODBC]] \- [[TParadox/ja|Paradox]] \- [[SQLite/ja|SQLite]] \- [[Lazarus Tdbf Tutorial/ja|dBASE]] \- [[MS Access/ja|MS Access]] \- [[Zeos tutorial/ja|Zeos]]
4+**日本語版メニュー**
5+---
6+[[Main Page/ja|メインページ]] \- [[Lazarus Documentation/ja|Lazarus Documentation日本語版]] \- [[Japanese Localization Notes|翻訳ノート]] \- [[Bug Tracking/ja|日本語障害情報]]
7+
8+
9+このテキストは「how-to」として作られている。数多くの質問に1つ、1つ答え、どのように様々なクラスを用いるのか説明したい。これらすべての質問は次から次へと沸き起こり、ある種のチュートリアルとなった。
210
3-このテキストがFree Pascal同様にLazarusでも用いられるように書くつもりだが、例はFree Pascal(即ち、コンソールアプリケーション)に向けてある。
11+このテキストがFree Pascal同様にLazarusでも用いられるように書くつもりだが、例はFree Pascal(即ち、コンソールアプリケーション)に向けてある。
412
513## どこで公式のドキュメンテーションが見つかるか
614
7-公式ドキュメンテーションはここを参照されたい[SQLDBドキュメンテーション](http://www.freepascal.org/docs-html/fcl/sqldb/index.html)。
15+公式ドキュメンテーションはここを参照されたい[SQLDBドキュメンテーション](<http://www.freepascal.org/docs-html/fcl/sqldb/index.html>)。
816
917## どのようにしてデータベースサーバに接続するか
1018
11-SqlDBは直接データベースサーバには接続せず、用いられているデータベースサーバに対応するクライアントを用いる。SqlDBはクライアントライブラリにコマンドを送り、クライアントライブラリがデータベースサーバに接続しコマンドを送る。これはデータベースと接続を持つためにクライアントライブラリがインストールされていなければならないことを意味する。Windowsではクライアントライブラリは通常、.dll、Linux では.so、OS/Xでは.dylibである。
12-
13-クライアントライブラリが適切にインストールされているときには、TSQLConnectionコンポーネントを用いてデータベースサーバに接続できる。様々なTSQLConnectionコンポーネントが異なるデータベースサーバに対して利用可能である([[SQLdb Package|SQLdb_Packageを]]参照):
19+SqlDBは直接データベースサーバには接続せず、用いられているデータベースサーバに対応するクライアントを用いる。SqlDBはクライアントライブラリにコマンドを送り、クライアントライブラリがデータベースサーバに接続しコマンドを送る。これはデータベースと接続を持つためにクライアントライブラリがインストールされていなければならないことを意味する。Windowsではクライアントライブラリは通常、.dll、Linux では.so、OS/Xでは.dylibである。
1420
15-- Firebird/Interbase: [[TIBConnection]]
16-- MS SQL Server: [[TMSSQLConnection]] (FPC 2.6.1から利用可能)
17-- MySQL v4.0: [[TMySQL40Connection]]
18-- MySQL v4.1: [[TMySQL41Connection]]
19-- MySQL v5.0: [[TMySQL50Connection]]
20-- MySQL v5.1: [[TMySQL51Connection]] (FPC version 2.5.1から利用可能)
21-- MySQL v5.5: [[TMySQL55Connection]] (Lazarus 1.0.8/FPC version 2.6.2から利用可能)
22-- MySQL v5.6: [[TMySQL56Connection]] (Lazarus 1.2.4/FPC version 2.6.4から利用可能)
23-- MySQL v5.7: [[TMySQL57Connection]] (訳注:いつから?)
24-- ODBC: [[TODBCConnection]] ([[ODBCConn|ODBCConn#TODBCConnectionを]]参照)
25-- Oracle: [[TOracleConnection]] ([[Oracle|Oracleを]]参照)
26-- PostgreSQL: [[TPQConnection]] ([[postgresql|postgresql#SQLDBを]]参照)
27-- Sqlite3: [[TSQLite3Connection/ja]] (FPC version 2.2.2から利用可能、[[SQLite|SQLite#Built-in_SQLDBを]]参照)
28-- Sybase ASE: [[TSybaseConnection]] (FPC 2.6.1から利用可能、[[Lazarus Database Overview|LazarusとMSSQL/Sybase]])
21+クライアントライブラリが適切にインストールされているときには、TSQLConnectionコンポーネントを用いてデータベースサーバに接続できる。様々なTSQLConnectionコンポーネントが異なるデータベースサーバに対して利用可能である([[SQLdb Package]]を参照):
2922
30-MySQLに対する注意 - クライアントとコネクションが相互交換できないほどクライアントバージョン間に多くの相違がある。もしクライアントライブラリ バージョン 4.1がインストールされているとすると、TMySQL41Connectionを用いなければならない。これはMySQLサーバには関連しておらずMySQL 4.1クライアントライブラリを用いて、おそらくMySQL 5.0サーバに接続できる(どの組み合わせがサポートされているかはMySQLドキュメンテーションを参照されたい)。
23+ * Firebird/Interbase: [[TIBConnection]]
24+ * MS SQL Server: [[TMSSQLConnection]] (FPC 2.6.1から利用可能)
25+ * MySQL v4.0: [[TMySQL40Connection]]
26+ * MySQL v4.1: [[TMySQL41Connection]]
27+ * MySQL v5.0: [[TMySQL50Connection]]
28+ * MySQL v5.1: [[TMySQL51Connection]] (FPC version 2.5.1から利用可能)
29+ * MySQL v5.5: [[TMySQL55Connection]] (Lazarus 1.0.8/FPC version 2.6.2から利用可能)
30+ * MySQL v5.6: [[TMySQL56Connection]] (Lazarus 1.2.4/FPC version 2.6.4から利用可能)
31+ * MySQL v5.7: [[TMySQL57Connection]] (訳注:いつから?)
32+ * ODBC: [[TODBCConnection/ja]] ([[ODBCConn/ja|ODBCConn/ja#TODBCConnection]]を参照)
33+ * Oracle: [[TOracleConnection]] ([[Oracle]]を参照)
34+ * PostgreSQL: [[TPQConnection]] ([[postgresql|postgresql#SQLDB]]を参照)
35+ * Sqlite3: [[TSQLite3Connection/ja]] (FPC version 2.2.2から利用可能、[[SQLite|SQLite#Built-in_SQLDB]]を参照)
36+ * Sybase ASE: [[TSybaseConnection]] (FPC 2.6.1から利用可能、[[Lazarus Database Overview|LazarusとMSSQL/Sybase]])
3137
32-さまざまなデータベースで細部は異なるが、一般的にデータベースサーバに接続するために4つのプロパティを設定しなければならない:
38+MySQLに対する注意 - クライアントとコネクションが相互交換できないほどクライアントバージョン間に多くの相違がある。もしクライアントライブラリ バージョン 4.1がインストールされているとすると、TMySQL41Connectionを用いなければならない。これはMySQLサーバには関連しておらずMySQL 4.1クライアントライブラリを用いて、おそらくMySQL 5.0サーバに接続できる(どの組み合わせがサポートされているかはMySQLドキュメンテーションを参照されたい)。
3339
34-- サーバの名前とIPアドレス
35-- データベースの名前
36-- ユーザー名
37-- パスワード
40+さまざまなデータベースで細部は異なるが、一般的にデータベースサーバに接続するために4つのプロパティを設定しなければならない:
3841
39-これらのプロパティが設定されると、サーバに「open」メソッドを作ることができる。もし接続に失敗するとEDatabaseError例外が生じる。データベースサーバに接続が確立しているかどうか確かめるために、「connected」プロパティを用いること。
42+ * サーバの名前とIPアドレス
43+ * データベースの名前
44+ * ユーザー名
45+ * パスワード
4046
41-``` pascal
47+これらのプロパティが設定されると、サーバに「open」メソッドを作ることができる。もし接続に失敗するとEDatabaseError例外が生じる。データベースサーバに接続が確立しているかどうか確かめるために、「connected」プロパティを用いること。
48+```
4249Program ConnectDB;
43-
44-{$mode objfpc}{$H+}
45-
46-uses
47- IBConnection;
48-
49-function CreateConnection: TIBConnection;
50-begin
51- result := TIBConnection.Create(nil);
52- result.Hostname := 'localhost';
53- result.DatabaseName := '/opt/firebird/examples/employee.fdb';
54- result.UserName := 'sysdba';
55- result.Password := 'masterkey';
56-end;
57-
58-var
59- AConnection : TIBConnection;
60-
61-begin
62- AConnection := CreateConnection;
63- AConnection.Open;
64- if Aconnection.Connected then
65- writeln('Successful connect!')
66- else
67- writeln('This is not possible, because if the connection failed, ' +
68- 'an exception should be raised, so this code would not ' +
69- 'be executed');
70- AConnection.Close;
71- AConnection.Free;
72-end.
50+
51+ {$mode objfpc}{$H+}
52+
53+ uses
54+ IBConnection;
55+
56+ function CreateConnection: TIBConnection;
57+ begin
58+ result := TIBConnection.Create(nil);
59+ result.Hostname := 'localhost';
60+ result.DatabaseName := '/opt/firebird/examples/employee.fdb';
61+ result.UserName := 'sysdba';
62+ result.Password := 'masterkey';
63+ end;
64+
65+ var
66+ AConnection : TIBConnection;
67+
68+ begin
69+ AConnection := CreateConnection;
70+ AConnection.Open;
71+ if Aconnection.Connected then
72+ writeln('Successful connect!')
73+ else
74+ writeln('This is not possible, because if the connection failed, ' +
75+ 'an exception should be raised, so this code would not ' +
76+ 'be executed');
77+ AConnection.Close;
78+ AConnection.Free;
79+ end.
7380```
7481
75-もし、エラーが発生したら、注意してエラーメッセージを読むこと。データベースサーバが稼働していない、ユーザー名もしくはパスワードが誤っている、データベース名またはIPアドレスが誤って入力されたかもしれない。もしエラーメッセージがクライアントライブラリが見つからないと言っているなら、クライアントライブラリが正しくインストールされているか確かめること。しばしばエラーメッセージは探しているファイル名を文字通り言う。
82+もし、エラーが発生したら、注意してエラーメッセージを読むこと。データベースサーバが稼働していない、ユーザー名もしくはパスワードが誤っている、データベース名またはIPアドレスが誤って入力されたかもしれない。もしエラーメッセージがクライアントライブラリが見つからないと言っているなら、クライアントライブラリが正しくインストールされているか確かめること。しばしばエラーメッセージは探しているファイル名を文字通り言う。
7683
7784## どのようにして直接クエリを実行/テーブルを作るのか
7885
79-SqlDB - 文字通り名前がすべてを体現している - はSQLを用いて唯一、データベースサーバとやり取りをする。SQL は 「Structured Query Language」を意味する。 SQLはリレーショナルデータベースとやり取りすることを可能にするために開発された言語である。実際にはすべてのデータベースシステムはそれぞれ方言を持っているが、SQLステートメントの多くはすべてのデータベースシステムで共通している。
80-
81-FPCでは、以下の違いがある:
86+SqlDB - 文字通り名前がすべてを体現している - はSQLを用いて唯一、データベースサーバとやり取りをする。SQL は 「Structured Query Language」を意味する。 SQLはリレーショナルデータベースとやり取りすることを可能にするために開発された言語である。実際にはすべてのデータベースシステムはそれぞれ方言を持っているが、SQLステートメントの多くはすべてのデータベースシステムで共通している。
8287
83-- 情報(データセット)を返すSQLステートメント。このため、TSQLQueryコンポーネントを用いなければならない; #How to read data from a table?を参照のこと。
84-- 情報を返さずに、変わって何かを行うステートメント、例えば、データを更新する。このため、またTSQLConnectionの「ExecuteDirect」メソッドを使うかもしれない(データセットを引き戻すためにこれを使うこともできるが、結果に興味はない、例えばセレクタブルストアドプロシージャ)。
88+FPCでは、以下の違いがある:
8589
86-大半のデータベースシステムはトランザクションでSQLステートメントを実行する。もし、他のトランザクションの中で利用できるトランザクションの中で行われる変更を望む、もしくはトランザクションが閉じた後でそれらの変更する(!)ならば、トランザクションを「commit」しなければならない。
90+ * 情報(データセット)を返すSQLステートメント。このため、TSQLQueryコンポーネントを用いなければならない; #How to read data from a table?を参照のこと。
91+ * 情報を返さずに、変わって何かを行うステートメント、例えば、データを更新する。このため、またTSQLConnectionの「ExecuteDirect」メソッドを使うかもしれない(データセットを引き戻すためにこれを使うこともできるが、結果に興味はない、例えばセレクタブルストアドプロシージャ)。
8792
88-トランザクションをサポートするために、SqlDBはTSQLTransactionコンポーネントを含んでいる。SqlDBによって実行されるSQLステートメントはデータベースシステムが、トランザクションをサポートしていなくとも、常にトランザクションの最中に行われる必要がある。同様に、TSQLTransactionがいまだにサポートしていないトランザクションをサポートしているデータベースシステムも存在する。その時ですらTSQLTransactionコンポーネントを使わなければならない。
93+大半のデータベースシステムはトランザクションでSQLステートメントを実行する。もし、他のトランザクションの中で利用できるトランザクションの中で行われる変更を望む、もしくはトランザクションが閉じた後でそれらの変更する(!)ならば、トランザクションを「commit」しなければならない。
8994
90-SQLステートメントを実行するために`TSQLConnection.ExecuteDirect`を使うには、どの「Transaction」が使われなければならないかを明示しなければならない。逆に、TSQLTransactionを使うためには、どのTSQLTransactionコンポーネントが使われるかを明示しなければならない。
95+トランザクションをサポートするために、SqlDBはTSQLTransactionコンポーネントを含んでいる。SqlDBによって実行されるSQLステートメントはデータベースシステムが、トランザクションをサポートしていなくとも、常にトランザクションの最中に行われる必要がある。同様に、TSQLTransactionがいまだにサポートしていないトランザクションをサポートしているデータベースシステムも存在する。その時ですらTSQLTransactionコンポーネントを使わなければならない。
9196
92-以下の例は「NAME」と「ID」フィールドを持つ「TBLNAMES」を生成し2つのレコードを挿入する。今回はSQLiteを用いる。使われるSQLステートメントは説明されない。SQLステートメント、その使用と文法に関しては、データベースシステムのドキュメンテーションを参照されたい。 この例ではいかなるエラーの捕捉も試みないことに注意すること、それは悪いことである! [例外](https://www.freepascal.org/docs-html/current/ref/refch17.html#x226-24800017)を調べていただきたい。
97+SQLステートメントを実行するために`TSQLConnection.ExecuteDirect`を使うには、どの「Transaction」が使われなければならないかを明示しなければならない。逆に、TSQLTransactionを使うためには、どのTSQLTransactionコンポーネントが使われるかを明示しなければならない。
9398
94-``` pascal
99+以下の例は「NAME」と「ID」フィールドを持つ「TBLNAMES」を生成し2つのレコードを挿入する。今回はSQLiteを用いる。使われるSQLステートメントは説明されない。SQLステートメント、その使用と文法に関しては、データベースシステムのドキュメンテーションを参照されたい。 この例ではいかなるエラーの捕捉も試みないことに注意すること、それは悪いことである! [例外](<https://www.freepascal.org/docs-html/current/ref/refch17.html#x226-24800017>)を調べていただきたい。
100+```
95101program CreateTable;
96-{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
97-uses
98- sqldb, sqlite3conn;
99-
100-var
101- AConnection : TSQLite3Connection;
102- ATransaction : TSQLTransaction;
103-
104-begin
105- AConnection := TSQLite3Connection.Create(nil);
106- AConnection.DatabaseName := 'test_dbase';
107-
108- ATransaction := TSQLTransaction.Create(AConnection);
109- AConnection.Transaction := ATransaction;
110- AConnection.Open;
111- ATransaction.StartTransaction;
112- AConnection.ExecuteDirect('create table TBLNAMES (ID integer, NAME varchar(40));');
113-
114- ATransaction.Commit;
115-
116- ATransaction.StartTransaction;
117- AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (1,''Name1'');');
118- AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (2,''Name2'');');
119- ATransaction.Commit;
120- AConnection.Close;
121- ATransaction.Free;
122- AConnection.Free;
123-end.
102+ {$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
103+ uses
104+ sqldb, sqlite3conn;
105+
106+ var
107+ AConnection : TSQLite3Connection;
108+ ATransaction : TSQLTransaction;
109+
110+ begin
111+ AConnection := TSQLite3Connection.Create(nil);
112+ AConnection.DatabaseName := 'test_dbase';
113+
114+ ATransaction := TSQLTransaction.Create(AConnection);
115+ AConnection.Transaction := ATransaction;
116+ AConnection.Open;
117+ ATransaction.StartTransaction;
118+ AConnection.ExecuteDirect('create table TBLNAMES (ID integer, NAME varchar(40));');
119+
120+ ATransaction.Commit;
121+
122+ ATransaction.StartTransaction;
123+ AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (1,''Name1'');');
124+ AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (2,''Name2'');');
125+ ATransaction.Commit;
126+ AConnection.Close;
127+ ATransaction.Free;
128+ AConnection.Free;
129+ end.
124130```
125131
126132## どのようにしてテーブルからデータを取得するのか
127133
128-テーブルからデータを読み込むときにはTSQLQueryを用いること。TSQLQueryコンポーネントはその仕事をするために、TSQLConnectionコンポーネントとTSQLTransactionコンポーネントに接続されなければない。TSQLConnectionとTSQLTransactionの設定は#How to connect to a database server?と#How to execute direct queries/make a table?で議論する。
129-
130-TSQLConnectionの時、TSQLTransactionとTSQLQueryが接続される、そしてTSQLQueryは動作するためにさらに設定される。TSQLQueryはTStringsオブジェクトを含む「SQL」プロパティを持つ。「SQL」プロパティは実行されるべきSQLステートメントを含んでいる。もしテーブル`tablename`のすべてのデータを読まなければならないときには、「SQL」プロパティを以下のように設定する:
134+テーブルからデータを読み込むときにはTSQLQueryを用いること。TSQLQueryコンポーネントはその仕事をするために、TSQLConnectionコンポーネントとTSQLTransactionコンポーネントに接続されなければない。TSQLConnectionとTSQLTransactionの設定は#How to connect to a database server? と#How to execute direct queries/make a table?で議論する。
131135
132-``` sql
136+TSQLConnectionの時、TSQLTransactionとTSQLQueryが接続される、そしてTSQLQueryは動作するためにさらに設定される。TSQLQueryはTStringsオブジェクトを含む「SQL」プロパティを持つ。「SQL」プロパティは実行されるべきSQLステートメントを含んでいる。もしテーブル`tablename`のすべてのデータを読まなければならないときには、「SQL」プロパティを以下のように設定する:
137+```
133138'SELECT * FROM tablename;'
134139```
135140
136-サーバからテーブルを読み込み、TSQLQueryデータセットにデータを読み込むには「open」を使うこと。データは「close」を用いてクエリが閉じられるまでTSQLQueryを通してアクセスできる。
141+サーバからテーブルを読み込み、TSQLQueryデータセットにデータを読み込むには「open」を使うこと。データは「close」を用いてクエリが閉じられるまでTSQLQueryを通してアクセスできる。
137142
138-TSQLQueryはTDatasetのサブクラスである。TDatasetはテーブルのすべてのカラムを含む「Field」コレクションを持っている。TDatasetはまた、現在のレコードを追跡する。現在のレコードを変更するために「First」、「Next」、「Prior」、「Last」を用いること。もし最初のレコードが届いたら「Bof」が「True」となり、もし最後のレコードに達したら、「Eof」が「True」になる。現在のレコードの値を読むためには初めに正しい「TField」オブジェクトを見つけ、そして「AsString」、「AsInteger」を用いること。
143+TSQLQueryはTDatasetのサブクラスである。TDatasetはテーブルのすべてのカラムを含む「Field」コレクションを持っている。TDatasetはまた、現在のレコードを追跡する。現在のレコードを変更するために「First」、「Next」、「Prior」、「Last」を用いること。もし最初のレコードが届いたら「Bof」が「True」となり、もし最後のレコードに達したら、「Eof」が「True」になる。現在のレコードの値を読むためには初めに正しい「TField」オブジェクトを見つけ、そして「AsString」、「AsInteger」を用いること。
139144
140145### 例: テーブルからデータを取得する
141146
142-以下は上のCreateTable例で作られたテーブルのすべての値を表示する例である。test_databaseファイルをShowDataワーキングディレクトリにコピーすること。エラーチェックを行っていないことに再び注意すること!
143-
144-``` pascal
147+以下は上のCreateTable例で作られたテーブルのすべての値を表示する例である。test_databaseファイルをShowDataワーキングディレクトリにコピーすること。エラーチェックを行っていないことに再び注意すること!
148+```
145149Program ShowData;
146- {$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
147-uses
148- DB, Sysutils, sqldb, sqlite3conn;
149-
150-var
151- AConnection : TSQLConnection;
152- ATransaction : TSQLTransaction;
153- Query : TSQLQuery;
154-
155-begin
156- AConnection := TSQLite3Connection.Create(nil);
157- ATransaction := TSQLTransaction.Create(AConnection);
158- AConnection.Transaction := ATransaction;
159- AConnection.DatabaseName := 'test_dbase';
160- Query := TSQLQuery.Create(nil);
161- Query.SQL.Text := 'select * from tblNames';
162- Query.Database := AConnection;
163- Query.Open;
164- while not Query.Eof do
165- begin
166- Writeln('ID: ', Query.FieldByName('ID').AsInteger, 'Name: ' +
167- Query.FieldByName('Name').AsString);
168- Query.Next;
169- end;
170- Query.Close;
171- AConnection.Close;
172- Query.Free;
173- ATransaction.Free;
174- AConnection.Free;
175-end.
150+ {$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
151+ uses
152+ DB, Sysutils, sqldb, sqlite3conn;
153+
154+ var
155+ AConnection : TSQLConnection;
156+ ATransaction : TSQLTransaction;
157+ Query : TSQLQuery;
158+
159+ begin
160+ AConnection := TSQLite3Connection.Create(nil);
161+ ATransaction := TSQLTransaction.Create(AConnection);
162+ AConnection.Transaction := ATransaction;
163+ AConnection.DatabaseName := 'test_dbase';
164+ Query := TSQLQuery.Create(nil);
165+ Query.SQL.Text := 'select * from tblNames';
166+ Query.Database := AConnection;
167+ Query.Open;
168+ while not Query.Eof do
169+ begin
170+ Writeln('ID: ', Query.FieldByName('ID').AsInteger, 'Name: ' +
171+ Query.FieldByName('Name').AsString);
172+ Query.Next;
173+ end;
174+ Query.Close;
175+ AConnection.Close;
176+ Query.Free;
177+ ATransaction.Free;
178+ AConnection.Free;
179+ end.
176180```
177181
178182もちろん、上記のコードは未完成で、「try...finally」ブロックを欠く。しかし、上のコードはデータベースコードを示す意図のもので、そのため仕上げの一筆は省いてある。 「TSQLTransaction.StartTransaction」が使われてないことに注意してほしい。これは不要である。TSQLQueryが開かれるとき、SQLステートメントが実行され、もしトランザクションが利用できないときにはトランザクションが自動的に始まる。プログラマは明示的にトランザクションを開始させる必要はない。 同様のことがTSQLConnectionによって維持されている接続にも適用される。接続は必要に応じて開かれ、「Aconnection.Open」は全く必要ない。もし、TSQLTransactionが破棄されると、自動的「rollback」が実行される。**トランザクションに含まれるデータに対する、ありえる変更は失われるだろう。**
179183
180184### なぜ TSQLQuery.RecordCount はいつも10を返すのか
181185
182-データセットのレコードを数えるためには、「.RecordCount」を用いること。しかし、「.RecordCount」はサーバからすでに送り出されたレコードの数を示している。性能上の理由により、SqlDBはデフォルトではTSQLQueryを開いたときすべてのレコードを読まず、最初の10を読む。11番目のレコードを読むときのみに次の10レコードがアクセスされる、など。「.Last」を用いると、すべてのレコードが読み込まれる。 サーバにあるレコードの真の数を知りたいときは、初めに「.Last」、そして「.RecordCount」を呼ぶことができる。 また別のやり方もある。サーバによって返されるレコードの数は「.PacketRecords」プロパティにセットされる。そのデフォルト値は10、これを-1に設定すると、一度にすべてのレコードが読み込まれる。
186+データセットのレコードを数えるためには、「.RecordCount」を用いること。しかし、「.RecordCount」はサーバからすでに送り出されたレコードの数を示している。性能上の理由により、SqlDBはデフォルトではTSQLQueryを開いたときすべてのレコードを読まず、最初の10を読む。11番目のレコードを読むときのみに次の10レコードがアクセスされる、など。「.Last」を用いると、すべてのレコードが読み込まれる。 サーバにあるレコードの真の数を知りたいときは、初めに「.Last」、そして「.RecordCount」を呼ぶことができる。 また別のやり方もある。サーバによって返されるレコードの数は「.PacketRecords」プロパティにセットされる。そのデフォルト値は10、これを-1に設定すると、一度にすべてのレコードが読み込まれる。
183187
184-現在の安定版のFPCでは、.RecordCountはフィルタを考慮に入れていない。即ち、それはフィルタをかけられない総和となる。
188+現在の安定版のFPCでは、.RecordCountはフィルタを考慮に入れていない。即ち、それはフィルタをかけられない総和となる。
185189
186-もしレコードの正確な数を必要としているのであれば、ほかのSQLクエリをクエリの中で用いてレコードの数を直接問い合わせるのがしばしばより良い考えであるが、その間に他のトランザクションがレコードの数を変えたかもしれないので、同じトランザクションの中でそれをしなければならないだろう。
190+もしレコードの正確な数を必要としているのであれば、ほかのSQLクエリをクエリの中で用いてレコードの数を直接問い合わせるのがしばしばより良い考えであるが、その間に他のトランザクションがレコードの数を変えたかもしれないので、同じトランザクションの中でそれをしなければならないだろう。
187191
192+
193+
188194### Lazarus
189195
190-Lazarusはフォーム上にTDatasetからのデータを示すために様々なコンポーネントを持っている。正しいTSQLConnection、TSQLTransaction、TSQLQueryコンポーネントをフォームに置き、そしてそれらを適切に接続、設定すること。加えて、TDatasourceが必要となり、「TDatasource.Dataset」プロパティを、用いるTSQLQueryコンポーネントに設定すること。 (**注意**「TSQLQuery.Datasource」プロパティを、用いるTDatasourceコンポーネントに設定しないこと。「TSQLQuery.Datasource」プロパティはmaster-detailテーブルのみに使われる - [[MasterDetail]]参照)。結果としてTDGridをフォームに配置して、前に加えたTDatasourceをグリッドのプロパティに設定するることになる。
196+Lazarusはフォーム上にTDatasetからのデータを示すために様々なコンポーネントを持っている。正しいTSQLConnection、TSQLTransaction、TSQLQueryコンポーネントをフォームに置き、そしてそれらを適切に接続、設定すること。加えて、TDatasourceが必要となり、「TDatasource.Dataset」プロパティを、用いるTSQLQueryコンポーネントに設定すること。 (**注意** 「TSQLQuery.Datasource」プロパティを、用いるTDatasourceコンポーネントに設定しないこと。「TSQLQuery.Datasource」プロパティはmaster-detailテーブルのみに使われる - [[MasterDetail]]参照)。結果としてTDGridをフォームに配置して、前に加えたTDatasourceをグリッドのプロパティに設定するることになる。
191197
192-これらすべてが機能していることを見るために、TSQLConnectionの「Connected」プロパティをLazarus IDEで「True」に設定すること。IDEはデータベースサーバへ直ちに接続を試みるだろう。もし、これが動いたら、「TSQLQuery.Active」プロパティを「True」に設定できる。もしすべてが正しいなら、IDEの中に、直ちにテーブルからのすべてのデータがみられるだろう。
198+これらすべてが機能していることを見るために、TSQLConnectionの「Connected」プロパティをLazarus IDEで「True」に設定すること。IDEはデータベースサーバへ直ちに接続を試みるだろう。もし、これが動いたら、「TSQLQuery.Active」プロパティを「True」に設定できる。もしすべてが正しいなら、IDEの中に、直ちにテーブルからのすべてのデータがみられるだろう。
193199
194200## どのようにしてテーブルのデータを変更するのか
195201
196-レコード内のデータを変更するための一般的なプロセスは、TSQLQuery を取得して変更するレコードを検索し、そこで変更を加えてデータベースにプッシュし直すことである。[[TDataSet]] (TSQLQuery の派生元) は編集モードに設定する必要がある。 編集モードに入るには、「.Edit」、「.Insert」、または「.Append」メソッドを呼び出す。 現在のレコードを変更するには、「.Edit」メソッドを使用する。現在のレコードを変更するには、「.Edit」メソッドを使用する。 現在のレコードの前に新しいレコードを挿入するには、「.Insert」を使用する。 テーブルの最後に新しいレコードを挿入するには、「.Append」を使用する。編集モードでは、「フィールド」プロパティを通じてフィールド値を変更できる。「Post」を使用して新しいデータを検証する。データが有効な場合は、編集モードが終了する。たとえば「.Next」を使用して別のレコードに移動し、データセットが編集モードの場合、最初に「.Post」が呼び出される。「.Cancel」 を使用すると、最後の 「.Post」 呼び出し以降に加えたすべての変更が破棄され、編集モードが終了します。
197-
198-``` pascal
202+レコード内のデータを変更するための一般的なプロセスは、TSQLQuery を取得して変更するレコードを検索し、そこで変更を加えてデータベースにプッシュし直すことである。[[TDataSet]] (TSQLQuery の派生元) は編集モードに設定する必要がある。 編集モードに入るには、「.Edit」、「.Insert」、または「.Append」メソッドを呼び出す。 現在のレコードを変更するには、「.Edit」メソッドを使用する。現在のレコードを変更するには、「.Edit」メソッドを使用する。 現在のレコードの前に新しいレコードを挿入するには、「.Insert」を使用する。 テーブルの最後に新しいレコードを挿入するには、「.Append」を使用する。編集モードでは、「フィールド」プロパティを通じてフィールド値を変更できる。「Post」を使用して新しいデータを検証する。データが有効な場合は、編集モードが終了する。たとえば「.Next」を使用して別のレコードに移動し、データセットが編集モードの場合、最初に「.Post」が呼び出される。「.Cancel」 を使用すると、最後の 「.Post」 呼び出し以降に加えたすべての変更が破棄され、編集モードが終了します。
203+```
199204Query.Edit;
200-Query.FieldByName('NAME').AsString := 'Edited name';
201-Query.Post;
205+ Query.FieldByName('NAME').AsString := 'Edited name';
206+ Query.Post;
202207```
203208
204-上記はまだ完全な話ではない。 TSQLQuery は、バッファされた更新を利用する TBufDataset から派生している。バッファ更新とは、「Post」を呼び出した後、データセット内の変更がすぐに表示されるが、データベース サーバーには送信されないことを意味する。実際に起こるのは、変更が変更ログに保持されることである。「.ApplyUpdates」メソッドが呼び出されると、変更ログ内のすべての変更がデータベースに送信される。そうして初めて、データベース サーバーは変更を認識する。変更は、TSQLTransaction のトランザクション内でサーバーに送信される。「ApplyUpdates」の前にトランザクションを正しく設定すること。更新を適用した後、コミットを実行して変更をデータベース サーバーに保存する必要がある。
205-
206-以下は、テーブル内のデータを変更し、変更をサーバーに送信し、トランザクションをコミットする例である。 繰り返すが、エラーチェックがない。これは非常に芳しくない!
209+上記はまだ完全な話ではない。 TSQLQuery は、バッファされた更新を利用する TBufDataset から派生している。バッファ更新とは、「Post」を呼び出した後、データセット内の変更がすぐに表示されるが、データベース サーバーには送信されないことを意味する。実際に起こるのは、変更が変更ログに保持されることである。「.ApplyUpdates」メソッドが呼び出されると、変更ログ内のすべての変更がデータベースに送信される。そうして初めて、データベース サーバーは変更を認識する。変更は、TSQLTransaction のトランザクション内でサーバーに送信される。「ApplyUpdates」の前にトランザクションを正しく設定すること。更新を適用した後、コミットを実行して変更をデータベース サーバーに保存する必要がある。
207210
208-``` pascal
211+以下は、テーブル内のデータを変更し、変更をサーバーに送信し、トランザクションをコミットする例である。 繰り返すが、エラーチェックがない。これは非常に芳しくない!
212+```
209213Program EditData;
210-{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
211-uses
212- db, sqldb, sqlite3conn;
213-var
214- AConnection : TSQLConnection;
215- ATransaction : TSQLTransaction;
216- Query : TSQLQuery;
217-
218-begin
219- AConnection := TSQLite3Connection.Create(nil);
220- ATransaction := TSQLTransaction.Create(AConnection);
221- AConnection.Transaction := ATransaction;
222- AConnection.DatabaseName := 'test_dbase';
223- Query := TSQLQuery.Create(nil);
224- Query.DataBase := AConnection;
225- Query.SQL.Text := 'select * from tblNames where ID = 2';
226- Query.Open;
227- Query.Edit;
228- Query.FieldByName('NAME').AsString := 'Name Number 2';
229- Query.Post;
230- Query.UpdateMode := upWhereAll; // dbで定義されている
231- Query.ApplyUpdates;
232- ATransaction.Commit;
233- Query.Free;
234- ATransaction.Free;
235- AConnection.Free;
236-end.
214+ {$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
215+ uses
216+ db, sqldb, sqlite3conn;
217+ var
218+ AConnection : TSQLConnection;
219+ ATransaction : TSQLTransaction;
220+ Query : TSQLQuery;
221+
222+ begin
223+ AConnection := TSQLite3Connection.Create(nil);
224+ ATransaction := TSQLTransaction.Create(AConnection);
225+ AConnection.Transaction := ATransaction;
226+ AConnection.DatabaseName := 'test_dbase';
227+ Query := TSQLQuery.Create(nil);
228+ Query.DataBase := AConnection;
229+ Query.SQL.Text := 'select * from tblNames where ID = 2';
230+ Query.Open;
231+ Query.Edit;
232+ Query.FieldByName('NAME').AsString := 'Name Number 2';
233+ Query.Post;
234+ Query.UpdateMode := upWhereAll; // dbで定義されている
235+ Query.ApplyUpdates;
236+ ATransaction.Commit;
237+ Query.Free;
238+ ATransaction.Free;
239+ AConnection.Free;
240+ end.
237241```
238242
239-実際の作業は、変更するレコードを識別する SQL ステートメント「select * from tblNames where ID = 2」から始まる。 「where ID = 2」ビットを省略すると、TSQLQuery は明らかに ID (および他の整数フィールド?) を 1 に設定する。そのため、ID=1 の行のみで動作する。「UpdateMode」については、引き続き読み進められたい。
243+実際の作業は、変更するレコードを識別する SQL ステートメント「select * from tblNames where ID = 2」から始まる。 「where ID = 2」ビットを省略すると、TSQLQuery は明らかに ID (および他の整数フィールド?) を 1 に設定する。そのため、ID=1 の行のみで動作する。「UpdateMode」については、引き続き読み進められたい。
240244
241245## どのようにして SqlDB はデータベースサーバに変更を送るのか
242246
243-#どのようにしてテーブルのデータを変更するのかのコード例で以下が、何をしているのか説明なしに記載されている。
244-
245-``` pascal
247+#どのようにしてテーブルのデータを変更するのかのコード例で以下が、何をしているのか説明なしに記載されている。
248+```
246249Query.UpdateMode := upWhereAll;
247250```
248251
249-その行が何をしているのかを知る最良の方法は、その行を省略することだ。 このステートメントを省略し、この Howto に正確に従った場合、次のエラー メッセージが表示される:
250-
251-```text
252+その行が何をしているのかを知る最良の方法は、その行を省略することだ。 このステートメントを省略し、この Howto に正確に従った場合、次のエラー メッセージが表示される:
253+```
252254No update query specified and failed to generate one. (No fields for inclusion in where statement found)
253255```
254256
255-何が問題なのかを理解するには、変更がどのようにデータベース サーバーに送信されるかを理解する必要がある。SQL サーバー内のデータを取得する唯一の方法は、SQL クエリを実行することだ。SQL には、レコードを操作する 3 つの異なる方法に対応する 3 種類のクエリがある。新しいレコードの作成、レコードの変更または削除には、それぞれ、insert、update、delete ステートメントが実行される。アップデートステートメントは以下のようなものだろう:
256-
257-``` sql
257+何が問題なのかを理解するには、変更がどのようにデータベース サーバーに送信されるかを理解する必要がある。SQL サーバー内のデータを取得する唯一の方法は、SQL クエリを実行することだ。SQL には、レコードを操作する 3 つの異なる方法に対応する 3 種類のクエリがある。新しいレコードの作成、レコードの変更または削除には、それぞれ、insert、update、delete ステートメントが実行される。アップデートステートメントは以下のようなものだろう:
258+```
258259update TBLNAMES set NAME='Edited name' where ID=1;
259260```
260261
261-変更をデータベース サーバーに送信するには、Sqldb は更新クエリを組み立てる必要がある。クエリを組み立てるには、以下の3つが必要である:
262+変更をデータベース サーバーに送信するには、Sqldb は更新クエリを組み立てる必要がある。クエリを組み立てるには、以下の3つが必要である:
262263
263-テーブルの名前
264+**テーブルの名前**
265+
264266テーブル名は選択クエリの解析から取得されるが、これは常に機能するとは限らない。
265267
266-`UPDATE` もしくは `INSERT` 句
268+**`UPDATE` もしくは `INSERT` 句**
269+
267270これらには、変更する必要があるフィールドが含まれている。
268271
269-`WHERE` 句
272+**`WHERE` 句**
273+
270274これには、どのレコードを変更する必要があるかを決定するフィールドが含まれる。
271275
272-すべてのフィールド(*Field*の各*TField*) には ProviderFlags プロパティがある。*ProviderFlags* に **pfInUpdate** があるフィールドのみが、クエリの更新または挿入条件で使用される。デフォルトではすべてのフィールドの *ProviderFlags* プロパティに *pfInUpdate* が設定されている。`WHERE` 句でどのフィールドが使用されるかは、クエリの *UpdateMode* プロパティとフィールドの *ProviderFlags* プロパティによって異なる。「ProviderFlags」に「pfInkey」が含まれるフィールドは、常に `WHERE` 句で使用されます。フィールドがテーブルの主キーの一部であり、「TSQLQuery.UsePrimaryKeyAsKey」が「True」を返す場合、フィールドには自動的に「pfInKey」フラグが設定されます。クエリの *UpdateMode* のデフォルト値は *upWhereKeyOnly* である。この更新モードでは、*ProviderFlags* プロパティに *pfInkey* を持つフィールドのみが `WHERE` 句で使用される。どのフィールドにも *pfInKey* フラグが設定されていない場合、`WHERE` 句に使用できるフィールドはなく、このセクションの冒頭のエラー メッセージが返される。
276+すべてのフィールド(_Field_ の各 _TField_) には ProviderFlags プロパティがある。 _ProviderFlags_ に **pfInUpdate** があるフィールドのみが、クエリの更新または挿入条件で使用される。デフォルトではすべてのフィールドの _ProviderFlags_ プロパティに _pfInUpdate_ が設定されている。`WHERE` 句でどのフィールドが使用されるかは、クエリの _UpdateMode_ プロパティとフィールドの _ProviderFlags_ プロパティによって異なる。「ProviderFlags」に「pfInkey」が含まれるフィールドは、常に `WHERE` 句で使用されます。フィールドがテーブルの主キーの一部であり、「TSQLQuery.UsePrimaryKeyAsKey」が「True」を返す場合、フィールドには自動的に「pfInKey」フラグが設定されます。クエリの _UpdateMode_ のデフォルト値は _upWhereKeyOnly_ である。この更新モードでは、 _ProviderFlags_ プロパティに _pfInkey_ を持つフィールドのみが `WHERE` 句で使用される。どのフィールドにも _pfInKey_ フラグが設定されていない場合、`WHERE` 句に使用できるフィールドはなく、このセクションの冒頭のエラー メッセージが返される。
273277
274-この問題は以下で解決される:
278+この問題は以下で解決される:
275279
276-- テーブルにプライマリキーを加え、*TSQLQuery.UsePrimaryKeyAsKey* を 「True」に設定するか、
277-- コードの中で*pfInkey*フラグを1つ、またはそれ以上のフィールドに設定する。
280+ * テーブルにプライマリキーを加え、 _TSQLQuery.UsePrimaryKeyAsKey_ を 「True」に設定するか、
281+ * コードの中で _pfInkey_ フラグを1つ、またはそれ以上のフィールドに設定する。
278282
279-**UpdateMode** プロパティは、さらに 2 つの可能な値を認識します。 「upWhereAll」を使用すると、「pfInWhere」フラグが `WHERE` 句に設定されているすべてのフィールドを追加できる。**UpdateMode**プロパティは2つの可能な値を知っている。デフォルトでは、すべてのフィールドにこのフラグが設定されている。「upWhereChanged」は 「pfInWhere」フラグセットを持つフィールド **および** 現在のレコードで、変更されたフィールドに用いることができる。
283+**UpdateMode** プロパティは、さらに 2 つの可能な値を認識します。 「upWhereAll」を使用すると、「pfInWhere」フラグが `WHERE` 句に設定されているすべてのフィールドを追加できる。**UpdateMode** プロパティは2つの可能な値を知っている。デフォルトでは、すべてのフィールドにこのフラグが設定されている。「upWhereChanged」は 「pfInWhere」フラグセットを持つフィールド **および** 現在のレコードで、変更されたフィールドに用いることができる。
280284
281285## エラーの取り扱い方
282286
283-実行時エラーは避けられず、ディスクがいっぱいになる、必要なライブラリやヘルパー アプリケーションが利用できない、等の問題が発生する可能性があるため、それを許容する必要がある。 FPC は実行時エラーを非常に適切に検出して処理する。通常、何が問題だったのかについて簡潔かつ合理的な説明が得られるが、多くの理由でエラーを監視し、取り扱うことを望むだろう -
284-
285-- おそらく、問題の最初の兆候が現れた時点でプログラムが終了することは望ましくないだろう。
286-- 続行する場合は、問題領域に割り当てられたメモリが回復されることを確認すること。メモリ リークは発生しないようにする。
287-- ただし、さらに詳しく説明する場合は、状況に応じた説明をユーザーに提供しよう。
287+実行時エラーは避けられず、ディスクがいっぱいになる、必要なライブラリやヘルパー アプリケーションが利用できない、等の問題が発生する可能性があるため、それを許容する必要がある。 FPC は実行時エラーを非常に適切に検出して処理する。通常、何が問題だったのかについて簡潔かつ合理的な説明が得られるが、多くの理由でエラーを監視し、取り扱うことを望むだろう -
288288
289-次のコードは上記の例に基づいているが、今回は重要な場所でのエラーをチェックをする。 鍵はtry...finally...end と try...except...end ブロックである。SQLite3をアンインストールして、test_dbaseのあったところにダミーファイルを置くなどして、これをテストすることができる。
289+ * おそらく、問題の最初の兆候が現れた時点でプログラムが終了することは望ましくないだろう。
290+ * 続行する場合は、問題領域に割り当てられたメモリが回復されることを確認すること。メモリ リークは発生しないようにする。
291+ * ただし、さらに詳しく説明する場合は、状況に応じた説明をユーザーに提供しよう。
290292
291-``` pascal
293+次のコードは上記の例に基づいているが、今回は重要な場所でのエラーをチェックをする。 鍵はtry...finally...end と try...except...end ブロックである。SQLite3をアンインストールして、test_dbaseのあったところにダミーファイルを置くなどして、これをテストすることができる。
294+```
292295program DemoDBaseWithErrors;
293-{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
294-uses
295- DB, Sysutils, sqldb, sqlite3conn;
296-var
297- Connect : TSQLite3Connection;
298- Trans : TSQLTransaction;
299-
300-procedure WriteTable (Command : string);
301-begin
302- Connect.ExecuteDirect(Command);
303- Trans.Commit;
304-end;
305-
306-procedure ReadTable ();
307-var
308- Query : TSQLQuery;
309- Count : smallint;
310-begin
311- Count := 0;
312- try
313- Query := TSQLQuery.Create(nil);
314- Query.DataBase := Connect;
315- Query.SQL.Text:= 'select * from tblNames';
316- Query.Open; // これは接続を開始する
317- while not Query.EOF do begin
318- writeln('ID: ', Query.FieldByName('ID').AsInteger, ' Name: ' +
319- Query.FieldByName('Name').AsString);
320- Query.Next;
321- Count := Count + 1;
296+ {$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
297+ uses
298+ DB, Sysutils, sqldb, sqlite3conn;
299+ var
300+ Connect : TSQLite3Connection;
301+ Trans : TSQLTransaction;
302+
303+
304+ procedure WriteTable (Command : string);
305+ begin
306+ Connect.ExecuteDirect(Command);
307+ Trans.Commit;
308+ end;
309+
310+ procedure ReadTable ();
311+ var
312+ Query : TSQLQuery;
313+ Count : smallint;
314+ begin
315+ Count := 0;
316+ try
317+ Query := TSQLQuery.Create(nil);
318+ Query.DataBase := Connect;
319+ Query.SQL.Text:= 'select * from tblNames';
320+ Query.Open; // これは接続を開始する
321+ while not Query.EOF do begin
322+ writeln('ID: ', Query.FieldByName('ID').AsInteger, ' Name: ' +
323+ Query.FieldByName('Name').AsString);
324+ Query.Next;
325+ Count := Count + 1;
326+ end;
327+ finally
328+ Query.Close;
329+ Query.Free;
322330 end;
323- finally
324- Query.Close;
325- Query.Free;
331+ writeln('Found a total of ' + InttoStr(Count) + ' lines.');
326332 end;
327- writeln('Found a total of ' + InttoStr(Count) + ' lines.');
328-end;
329-
330-procedure FatalError(ClassName, Message, Suggestion : string);
331-begin
332- writeln(ClassName);
333- writeln(Message);
334- writeln(Suggestion);
335- Connect.Close; // 解放することを心配するのはばかげているかもしれない。
336- Trans.free; // halt()を呼ぶつもりだが
337- Connect.Free; // これはデモだから、いいか ?
338- halt();
339-end;
340-
341-begin
342- Connect := TSQLite3Connection.Create(nil);
343- Trans := TSQLTransaction.Create(Connect);
344- Connect.Transaction := Trans;
345- Connect.DatabaseName := 'test_dbase';
346- try
347- if not fileexists(Connect.DatabaseName) then begin
348- Connect.Open; // もし例えばSQLiteがインストールされていないときにEInOutErrorをあげる
333+
334+ procedure FatalError(ClassName, Message, Suggestion : string);
335+ begin
336+ writeln(ClassName);
337+ writeln(Message);
338+ writeln(Suggestion);
339+ Connect.Close; // 解放することを心配するのはばかげているかもしれない。
340+ Trans.free; // halt()を呼ぶつもりだが
341+ Connect.Free; // これはデモだから、いいか ?
342+ halt();
343+ end;
344+
345+ begin
346+ Connect := TSQLite3Connection.Create(nil);
347+ Trans := TSQLTransaction.Create(Connect);
348+ Connect.Transaction := Trans;
349+ Connect.DatabaseName := 'test_dbase';
350+ try
351+ if not fileexists(Connect.DatabaseName) then begin
352+ Connect.Open; // もし例えばSQLiteがインストールされていないときにEInOutErrorをあげる
353+ Trans.StartTransaction;
354+ WriteTable('create table TBLNAMES (ID integer Primary Key, NAME varchar(40));');
355+ Trans.Commit;
356+ end;
357+ Connect.open;
349358 Trans.StartTransaction;
350- WriteTable('create table TBLNAMES (ID integer Primary Key, NAME varchar(40));');
351- Trans.Commit;
352- end;
353- Connect.open;
354- Trans.StartTransaction;
355- WriteTable('insert into TBLNAMES (NAME) values (''AName1'');');
356- WriteTable('insert into TBLNAMES (NAME) values (''AName2'');');
357- except
358- on E : EDatabaseError do
359- FatalError(E.ClassName, E.Message, 'Does the file contain the correct database ?');
360- on E : EInOutError do
361- FatalError(E.ClassName, E.Message, 'Have you installed SQLite (and dev package)?');
362- on E : Exception do
363- FatalError(E.ClassName, E.Message, 'Something really really bad happened.');
364- end;
365- ReadTable();
366- Connect.Close;
367- Trans.Free;
368- Connect.Free;
369-end.
359+ WriteTable('insert into TBLNAMES (NAME) values (''AName1'');');
360+ WriteTable('insert into TBLNAMES (NAME) values (''AName2'');');
361+ except
362+ on E : EDatabaseError do
363+ FatalError(E.ClassName, E.Message, 'Does the file contain the correct database ?');
364+ on E : EInOutError do
365+ FatalError(E.ClassName, E.Message, 'Have you installed SQLite (and dev package)?');
366+ on E : Exception do
367+ FatalError(E.ClassName, E.Message, 'Something really really bad happened.');
368+ end;
369+ ReadTable();
370+ Connect.Close;
371+ Trans.Free;
372+ Connect.Free;
373+ end.
370374```
371375
372376## どのようにしてTSQLQuery を用いてクエリを実行するのか
373377
374-次にデータセット(#どのようにしてテーブルからデータを取得するのか参照)を返すステートメントである。SQLはデータを返さないステートメントを持っている。例えば、`INSERT`、`UPDATE`、`DELETE`ステートメントはデータを返さない。これらは*TSQLConnection.ExecuteDirect*を用いることで実行できるが、TSQLQueryもまた用いることができる。もし、*TSQLQuery.Open* の代わりに *TSQLQuery.ExecSQL* を使って、データが変えることを期待しないなら、先に述べたように、SQLステートメントによりデータセットを開くために、*TSQLQuery.Open* を用いること。
375-
376-以下は TSQLQuery を用いてテーブルを作り、2つのレコードを作るプロシージャである。
378+次にデータセット(#どのようにしてテーブルからデータを取得するのか参照)を返すステートメントである。SQLはデータを返さないステートメントを持っている。例えば、`INSERT`、`UPDATE`、`DELETE`ステートメントはデータを返さない。これらは _TSQLConnection.ExecuteDirect_ を用いることで実行できるが、TSQLQueryもまた用いることができる。もし、 _TSQLQuery.Open_ の代わりに _TSQLQuery.ExecSQL_ を使って、データが変えることを期待しないなら、先に述べたように、SQLステートメントによりデータセットを開くために、 _TSQLQuery.Open_ を用いること。
377379
378-``` pascal
380+以下は TSQLQuery を用いてテーブルを作り、2つのレコードを作るプロシージャである。
381+```
379382procedure CreateTable;
380-
381-var
382- Query : TSQLQuery;
383-
384-begin
385- Query := TSQLQuery.Create(nil);
386- try
387- Query.Database := AConnection;
388-
389- Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
390- Query.ExecSQL;
391-
392- Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (1,''Name1'');';
393- Query.ExecSQL;
394-
395- Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (2,''Name2'');';
396- Query.ExecSQL;
397- finally
398- Query.Free;
399- end;
400-end;
383+
384+ var
385+ Query : TSQLQuery;
386+
387+ begin
388+ Query := TSQLQuery.Create(nil);
389+ try
390+ Query.Database := AConnection;
391+
392+ Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
393+ Query.ExecSQL;
394+
395+ Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (1,''Name1'');';
396+ Query.ExecSQL;
397+
398+ Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (2,''Name2'');';
399+ Query.ExecSQL;
400+ finally
401+ Query.Free;
402+ end;
403+ end;
401404```
402405
403406## どのようにしてクエリの中でパラメータを用いるのか
404407
405-In the code example of #どのようにしてTSQLQuery を用いてクエリを実行するのかのコード例の中で同じクエリが2回使われており、挿入される値が異なるだけである。これを行うより良い方法は、クエリの中でパラメータを用いることである。
406-
407-クエリ内のパラメータの構文はデータベース システムごとに異なるが、その違いは TSQLQuery によって処理される。
408+In the code example of #どのようにしてTSQLQuery を用いてクエリを実行するのかのコード例の中で同じクエリが2回使われており、挿入される値が異なるだけである。これを行うより良い方法は、クエリの中でパラメータを用いることである。
408409
409-クエリ内の値をコロンに置き換え、その後に使用するパラメータの名前を続ける。例えば:
410+クエリ内のパラメータの構文はデータベース システムごとに異なるが、その違いは TSQLQuery によって処理される。
410411
411-``` pascal
412+クエリ内の値をコロンに置き換え、その後に使用するパラメータの名前を続ける。例えば:
413+```
412414Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';
413415```
414416
415-このクエリは2つのパラメータ: 「ID」と「NAME」を作る。
416-
417-パラメーターを決定するために、*TSQLQuery.SQL* のテキストが割り当てられるか変更される時点でクエリが解析される。既存のパラメータはすべて削除され、新しいパラメータが「TSQLQuery.Params」プロパティに追加される。パラメーターに値を割り当てることは、データセット内のフィールドに値を割り当てることと似ている:
417+このクエリは2つのパラメータ: 「ID」と「NAME」を作る。
418418
419-``` pascal
419+パラメーターを決定するために、 _TSQLQuery.SQL_ のテキストが割り当てられるか変更される時点でクエリが解析される。既存のパラメータはすべて削除され、新しいパラメータが「TSQLQuery.Params」プロパティに追加される。パラメーターに値を割り当てることは、データセット内のフィールドに値を割り当てることと似ている:
420+```
420421Query.Params.ParamByName('Name').AsString := 'Name1';
421422```
422423
423-クエリからは、どのような種類のデータをパラメータに保存する必要があるかを知ることはできない。パラメータのデータ型は、パラメータに値が最初に割り当てられた時点で決定される。「.AsString」を使用して値を割り当てると、パラメータにはデータ型「ftString」が割り当てられる。'DataType' プロパティを設定することで、データ型を直接決定できる。不正なデータ型がパラメータに割り当てられている場合、クエリを開いたり実行したりするときに問題が発生する。 データ型についてのさらなる情報は [[Database field type]] を参照されたい。
424+クエリからは、どのような種類のデータをパラメータに保存する必要があるかを知ることはできない。パラメータのデータ型は、パラメータに値が最初に割り当てられた時点で決定される。「.AsString」を使用して値を割り当てると、パラメータにはデータ型「ftString」が割り当てられる。'DataType' プロパティを設定することで、データ型を直接決定できる。不正なデータ型がパラメータに割り当てられている場合、クエリを開いたり実行したりするときに問題が発生する。 データ型についてのさらなる情報は [[Database field type]] を参照されたい。
424425
425426### Select クエリ
426427
427-パラメーターを使用した選択クエリの例は、次のように変更することになる:
428-
429-``` pascal
430- Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = '''+Edit1.Text+''' ORDER BY NAME ';
428+パラメーターを使用した選択クエリの例は、次のように変更することになる:
431429```
432-
433-をこのように:
430+Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = '''+Edit1.Text+''' ORDER BY NAME ';
431+```
434432
435-``` pascal
436- Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = :NAMEPARAM ORDER BY NAME ';
437- Query.Params.ParamByName('NAMEPARAM').AsString := Edit1.Text;
433+をこのように:
438434```
435+Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = :NAMEPARAM ORDER BY NAME ';
436+ Query.Params.ParamByName('NAMEPARAM').AsString := Edit1.Text;
437+```
439438
440439### 実装例
441440
442-以下の例は1つ前の例と同じテーブルを生成するが、パラメータが用いられている:
443-
444-``` pascal
441+以下の例は1つ前の例と同じテーブルを生成するが、パラメータが用いられている:
442+```
445443procedure CreateTableUsingParameters;
446-
447-var
448- Query : TSQLQuery;
449-
450-begin
451- Query := TSQLQuery.Create(nil);
452- try
453- Query.Database := AConnection;
454-
455- Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
456- Query.ExecSQL;
457-
458- Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';
459- Query.Prepare;
460-
461- Query.Params.ParamByName('ID').AsInteger := 1;
462- Query.Params.ParamByName('NAME').AsString := 'Name1';
463- Query.ExecSQL;
464-
465- Query.Params.ParamByName('ID').AsInteger := 2;
466- Query.Params.ParamByName('NAME').AsString := 'Name2';
467- Query.ExecSQL;
468-
469- //Query.UnPrepare; // これを呼ぶ必要はない; Query.Closeによって呼ばれるはずである
470- Query.Close;
471- finally
472- Query.Free;
473- end;
474-end;
444+
445+ var
446+ Query : TSQLQuery;
447+
448+ begin
449+ Query := TSQLQuery.Create(nil);
450+ try
451+ Query.Database := AConnection;
452+
453+ Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
454+ Query.ExecSQL;
455+
456+ Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';
457+ Query.Prepare;
458+
459+ Query.Params.ParamByName('ID').AsInteger := 1;
460+ Query.Params.ParamByName('NAME').AsString := 'Name1';
461+ Query.ExecSQL;
462+
463+ Query.Params.ParamByName('ID').AsInteger := 2;
464+ Query.Params.ParamByName('NAME').AsString := 'Name2';
465+ Query.ExecSQL;
466+
467+ //Query.UnPrepare; // これを呼ぶ必要はない; Query.Closeによって呼ばれるはずである
468+ Query.Close;
469+ finally
470+ Query.Free;
471+ end;
472+ end;
475473```
476474
477-この例はパラメータを用いないコードよりもコード量が多くなることに気を付けること。ではパラメータの用途は何であろうか?
475+この例はパラメータを用いないコードよりもコード量が多くなることに気を付けること。ではパラメータの用途は何であろうか?
478476
479-速度が1つの理由である。このパラメータを用いた例はより実行が速い、何故なら(.Prepareステートメントもしくは最初の実行で)データベースサーバはクエリを1回のみパースするからである。
477+速度が1つの理由である。このパラメータを用いた例はより実行が速い、何故なら(.Prepareステートメントもしくは最初の実行で)データベースサーバはクエリを1回のみパースするからである。
480478
481-またプリペアードステートメントを用いる別の理由は、[SQL-インジェクション](http://en.wikipedia.org/wiki/SQL_injection)を防ぐことになる ([[Secure programming|Secure programmingも]]参照のこと)。
479+またプリペアードステートメントを用いる別の理由は、[SQL-インジェクション](<http://en.wikipedia.org/wiki/SQL_injection>)を防ぐことになる ([[Secure programming]]も参照のこと)。
482480
483-最後に、ある例ではコーディングを簡素化するためである。
481+最後に、ある例ではコーディングを簡素化するためである。
484482
485483## 問題解決法: TSQLConnection ログ
486484
487-TSQLConnection の動作をログに記録させることができる。 これは、Lazarus プログラムがデータベースに送信する内容を正確に確認したり、データベース コンポーネント自体をデバッグしたり、クエリを最適化したりする場合に便利である。 注意: 準備されたステートメント/パラメータ化されたクエリ (上記のセクションを参照) を使用する場合、パラメータは多くの場合、TSQLConnection の派生 (TIBConnection など) によってバイナリで送信されるため、ログに記録された SQL をコピーしてデータベース クエリ ツールに貼り付けるだけではすまない。いずれにせよ、接続ログにより、プログラムの動作について多くの洞察が得られる。
488-
489-これに代わるものとして:
485+TSQLConnection の動作をログに記録させることができる。 これは、Lazarus プログラムがデータベースに送信する内容を正確に確認したり、データベース コンポーネント自体をデバッグしたり、クエリを最適化したりする場合に便利である。 注意: 準備されたステートメント/パラメータ化されたクエリ (上記のセクションを参照) を使用する場合、パラメータは多くの場合、TSQLConnection の派生 (TIBConnection など) によってバイナリで送信されるため、ログに記録された SQL をコピーしてデータベース クエリ ツールに貼り付けるだけではすまない。いずれにせよ、接続ログにより、プログラムの動作について多くの洞察が得られる。
490486
491-1. デバッグを有効にして FPC (および Lazarus) をビルドした場合は、デバッガーを使用してデータベース コードをステップ実行できます。
492-2. ODBC ドライバーを使用している場合 (少なくとも Windows では)、ODBC コントロール パネルでトレースログ出力を有効にすることができる。
493-3. 多くのデータベースでは、特定の IP アドレス/接続から送信されるすべてのステートメントを監視できる。
487+これに代わるものとして:
494488
495-TSQLConnection ログを使用する場合は、2 つのことが必要である:
489+ 1. デバッグを有効にして FPC (および Lazarus) をビルドした場合は、デバッガーを使用してデータベース コードをステップ実行できます。
490+ 2. ODBC ドライバーを使用している場合 (少なくとも Windows では)、ODBC コントロール パネルでトレースログ出力を有効にすることができる。
491+ 3. 多くのデータベースでは、特定の IP アドレス/接続から送信されるすべてのステートメントを監視できる。
496492
497-1. TSQLConnection がログに記録する必要があるイベント タイプを指定する。
498-2. イベントを受信して処理する関数に TSQLConnection を指定する (イベントをファイルに記録したり、画面に出力したりするなど)。
493+TSQLConnection ログを使用する場合は、2 つのことが必要である:
499494
500-この関数は TDBLogNotifyEvent 型である必要があるため (sqldb.pp を参照)、次の署名が必要である:
495+ 1. TSQLConnection がログに記録する必要があるイベント タイプを指定する。
496+ 2. イベントを受信して処理する関数に TSQLConnection を指定する (イベントをファイルに記録したり、画面に出力したりするなど)。
501497
502-``` pascal
498+この関数は TDBLogNotifyEvent 型である必要があるため (sqldb.pp を参照)、次の署名が必要である:
499+```
503500TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;
504501```
505502
506503### FPC (もしくは: 手動的方法)
507504
508-コード スニペットでこれを説明できる:
509-
510-``` pascal
505+コード スニペットでこれを説明できる:
506+```
511507uses
512-...
513-TSQLConnection, //もしくはTIBConnection、TMSSQLConnection といった派生オブジェクト
514-...
515-var
516-type
517- TMyApplication = class(TCustomApplication); //これが接続を用いるアプリケーション
518-...
519- private
520- // この例はこの文字列リストにログを格納する:
521- FConnectionLog: TStringList;
522-...
523- protected
524- // このプロシージャは接続によるログのイベントを受け取るだろう:
525- procedure GetLogEvent(Sender: TSQLConnection; EventType: TDBEventType; Const Msg : String);
526-...
527- procedure TMyApplication.GetLogEvent(Sender: TSQLConnection;
528- EventType: TDBEventType; const Msg: String);
529- // TSQLConnectionによってプロシージャが呼ばれ、FConnectionLogに
530- // 受け取ったメッセージログが保存される
531- var
532- Source: string;
533- begin
534- // 見た目よく右揃え
535- case EventType of
536- detCustom: Source:='Custom: ';
537- detPrepare: Source:='Prepare: ';
538- detExecute: Source:='Execute: ';
539- detFetch: Source:='Fetch: ';
540- detCommit: Source:='Commit: ';
541- detRollBack: Source:='Rollback:';
542- else Source:='Unknown event. Please fix program code.';
543- end;
544- FConnectionLog.Add(Source + ' ' + Msg);
545- end;
546-
547-...
548- // 何をログに残したいか TSQLConnection に知らせる必要がある:
549- FConnection.LogEvents:=LogAllEvents; //= [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack]
550- // ... そして、どのプロシージャに向けて、接続がイベントを送るべきか:
551- FConnection.OnLog:=@Self.GetLogEvent;
552-...
553- // これで接続を使用できるようになり、FConnectionLog 文字列リストにログ メッセージが表示される
508+ ...
509+ TSQLConnection, //もしくはTIBConnection、TMSSQLConnection といった派生オブジェクト
510+ ...
511+ var
512+ type
513+ TMyApplication = class(TCustomApplication); //これが接続を用いるアプリケーション
514+ ...
515+ private
516+ // この例はこの文字列リストにログを格納する:
517+ FConnectionLog: TStringList;
518+ ...
519+ protected
520+ // このプロシージャは接続によるログのイベントを受け取るだろう:
521+ procedure GetLogEvent(Sender: TSQLConnection; EventType: TDBEventType; Const Msg : String);
522+ ...
523+ procedure TMyApplication.GetLogEvent(Sender: TSQLConnection;
524+ EventType: TDBEventType; const Msg: String);
525+ // TSQLConnectionによってプロシージャが呼ばれ、FConnectionLogに
526+ // 受け取ったメッセージログが保存される
527+ var
528+ Source: string;
529+ begin
530+ // 見た目よく右揃え
531+ case EventType of
532+ detCustom: Source:='Custom: ';
533+ detPrepare: Source:='Prepare: ';
534+ detExecute: Source:='Execute: ';
535+ detFetch: Source:='Fetch: ';
536+ detCommit: Source:='Commit: ';
537+ detRollBack: Source:='Rollback:';
538+ else Source:='Unknown event. Please fix program code.';
539+ end;
540+ FConnectionLog.Add(Source + ' ' + Msg);
541+ end;
542+
543+ ...
544+ // 何をログに残したいか TSQLConnection に知らせる必要がある:
545+ FConnection.LogEvents:=LogAllEvents; //= [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack]
546+ // ... そして、どのプロシージャに向けて、接続がイベントを送るべきか:
547+ FConnection.OnLog:=@Self.GetLogEvent;
548+ ...
549+ // これで接続を使用できるようになり、FConnectionLog 文字列リストにログ メッセージが表示される
554550```
555551
556-代わりに TSQLConnection の GlobalDBLogHook を使用して、複数の接続からすべてをログに記録することもできる。
552+代わりに TSQLConnection の GlobalDBLogHook を使用して、複数の接続からすべてをログに記録することもできる。
557553
558554### Lazarus (もしくは: 速い方法)
559555
560-最後に、上記の説明は、冒頭で示した FPC の方法である。 Lazarus を使用している場合、より簡単な方法は、TSQLConnection の OnLog イベントにイベント ハンドラーを割り当てることである。
556+最後に、上記の説明は、冒頭で示した FPC の方法である。 Lazarus を使用している場合、より簡単な方法は、TSQLConnection の OnLog イベントにイベント ハンドラーを割り当てることである。
561557
562558## 以下も参照のこと
563559
564-- [[Working With TSQLQuery]]
560+ * [[Working With TSQLQuery]]
565561
566562---
567-*From the Free Pascal wiki, page "SqlDBHowto/ja", as it stood on 2024-04-01 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).*
563+*From the Free Pascal wiki, page "SqlDBHowto/ja", as the Internet Archive kept it on 2025-01-17, last changed on 2024-09-24. 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).*

Back to history