Sign in Join
Wiki copytemporary

SQLdb Tutorial2/ja: what changed

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

OldNewLine
11## 概要
22
33[[SQLdb Tutorial1/ja|SQLdb Tutorial1/jaが]]済んでいるなら、データベースを表示する基本的なグリッドがあるはずだ このアプリケーションが機能するためには若干の改良を加えることができる。
44
55### 動的データベース接続
66
77これまでは、わかりやすくするために、固定のデータベース サーバー名、データベースの場所、ユーザー名、パスワードを使用してきた。 前述したように、「実際の」アプリケーションでは通常、ユーザーが独自のユーザー名とパスワードを指定できる。
88
99それらを指定できるようにフォームを変更しよう。標準メニューから 2 つの [[TEdit]] を追加する。 名前のプロパティを「ユーザー名」と「パスワード」に設定する。 肩越しに覗き見されることに対するセキュリティを確保するには、パスワードの PasswordChar プロパティを * (アスタリスク) に設定する。
1010
1111接続を簡単にしたい場合 (もちろん安全性は低くなるが)、UserName Text プロパティを SYSDBA などの有効なデータベース ユーザーに設定できる。 パスワード テキスト プロパティをマスターキーのようなデフォルト値に設定することもでき、セキュリティが重要でない場合は開発者のマシンで簡単にテストできるが...
1212
1313見た目上、ラベルを追加して何を入力すればよいのかわかるようにすると便利だ。
1414
1515また、Firebird/Interbase サーバー上の従業員サンプル データベースに簡単に接続できるように、サーバー名とデータベース パス用の 2 つのテキスト ボックスを追加する。 さらに 2 つの TEdit を追加し、ServerName と DatabaseName という名前を付ける。
1616
1717必要に応じて、「Text」プロパティを状況に応じたデフォルトの適切な値に設定できる。 localhost と `C:\Program Files\Firebird\Firebird_2_5\examples\empbuild\EMPLOYEE.FDB`
1818
1919ユーザーが入力する必要がある内容を説明するラベルもここで役に立つ。
2020
2121明確にするために、設計時コンポーネントから接続情報を削除する。[[TSQLConnector]] コンポーネントで、UserName、Password、DatabaseName、および HostName プロパティからすべてのテキストを削除する。
2222
2323さて、最後に、データベース接続コンポーネントに接続方法を指示する必要がある。 これは通常、アプリケーションの実行の開始時にのみ必要になる。 この例では、既存の「Button1」コードが接続をセットアップする良い方法である。
2424
2525以下が得られるまでコードを追加。
2626
2727``` pascal
2828procedure TForm1.Button1Click(Sender: TObject);
2929begin
3030 SQLQuery1.Close;
3131 //Firebird/Interbaseデータベースの接続設定
3232 // まだ接続していない場合にのみ必要:
3333 if not DBConnection.Connected then
3434 begin
3535 DBConnection.HostName := ServerName.Text;
3636 DBConnection.データベース名 := データベース名.テキスト;
3737 DBConnection.DatabaseName := DatabaseName.Text;
3838 DBConnection.Password := Password.Text;
3939 // これで接続が設定された。それを視覚的に示す。
4040 // 変更はもう行われない可能性がある
4141 ServerName.ReadOnly:=true;
4242 DatabaseName.ReadOnly:=true;
4343 UserName.ReadOnly:=true;
4444 Password.ReadOnly:=true;
4545 end;
4646 SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
4747 DBConnection.Connected:= True;
4848 SQLTransaction1.Active:= True;
4949 SQLQuery1.Open;
5050end;
5151```
5252
5353次に、実行して接続できるかどうかをテストする。
5454
5555#### SQLite、その他のデータベース
5656
5757必要に応じて、例えば SQLite の `employee.sqlite`、DatabaseName TEdit の Text、 プロパティを調整する。 。
5858
5959sqlite の場合、HostName、Username、および Password の指定は意味がないため、これらの TEdit を省略できる。 明らかに、上記のコードでは、対応する値を DBConnection に割り当てるのを省略またはコメントアウトする。 Firebird が埋め込まれている場合は、ユーザー名を SYSDBA にハードコーディングする。 sqlite を使用するときにはこれを指定しても問題ない。
6060
6161コードは次のようになる:
6262
6363``` pascal
6464procedure TForm1.Button1Click(Sender: TObject);
6565begin
6666 SQLQuery1.Close;
6767 //組み込みデータベースの接続設定
6868 // まだ接続していない場合にのみ必要:
6969 if not DBConnection.Connected then
7070 begin
7171 DBConnection.DatabaseName := DatabaseName.Text;
7272 DBConnection.UserName := 'SYSDBA'; //Firebird 埋め込みにはこれが必要。 SQLiteを使用する場合は問題ない
7373 // これで接続が設定された。それを視覚的に示す。
7474 // 変更はもう行われない可能性がある
7575 DatabaseName.ReadOnly:=true;
7676 end;
7777 SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
7878 DBConnection.Connected:= True;
7979 SQLTransaction1.Active:= True;
8080 SQLQuery1.Open;
8181end;
8282```
8383
8484### データのフィルタリング
8585
8686多くの場合、テーブルにはユーザーが見たくない大量のデータが含まれている (データベースからクエリを実行し、ネットワーク上を移動するには時間がかかる可能性がある)。米国からの顧客のみを表示する必要があると仮定する。 したがって、「SQLQuery1」の SQL 命令は次のようになる。
8787
8888``` SQL
8989select * from CUSTOMER where COUNTRY = 'USA'
9090```
9191
9292...これは、コードでは次のように変換される。
9393
9494``` pascal
9595SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = 'USA'';
9696```
9797
9898このサンプル アプリケーションでこの命令を使用しない理由は 2 つある。
9999
100100まず、単一引用符の使用法に問題がある。 コンパイラーは USA の前の引用符を終了引用符 (最初の引用符は select from... の前にある) として解釈するため、SQL 命令は無効になる。 解決策: 内側の引用符を 2 倍にする。
101101
102102``` pascal
103103SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = ''USA''';
104104```
105105
1061062 番目の、より重要な理由は、ユーザーがどのような制約でフィルターをかけたいのかがおそらくわからないという事実だ。 ユーザーの柔軟性を制限したくはない。
107107
108108この柔軟性を実現するには、まず SQL クエリ ステートメントを変更し、「USA」をプレースホルダー (SQL のパラメータ) に置き換える。Button1click プロシージャを変更して次のように置き換える。
109109
110110``` pascal
111111SQLQuery1.SQL.Text := 'select * from CUSTOMER';
112112```
113113
114114と:
115115
116116``` pascal
117117SQLQuery1.SQL.Text:= 'select * from CUSTOMER where COUNTRY = :COUNTRY';
118118```
119119
120120FPC SQLDB では、SQL パラメーターは先頭のコロンでマークされる (他の言語/環境では ? などの他の規則が使用されます)。 ユーザーがフィルターの値を入力できるようにするために、フォームに *TEdit* コンポーネントを配置する。 「Text」プロパティの値を削除する。
121121
122122これで、TEdit に入力されたテキストを取得し、TSQLQuery の 'Params' プロパティを使用して SQL COUNTRY パラメータを入力できるようになった。 これを前のステートメントの下に追加する。
123123
124124``` pascal
125125SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
126126```
127127
128128パラメータは位置または名前で指定できます。 名前を使用すると、ソース コードの読みやすさが向上し、既存のパラメーターの途中にさらにパラメーターを挿入する場合に明らかに役立つ。
129129
130130.AsString を使用して文字列値をパラメータに割り当てる。 整数パラメータ、ブール値パラメータなどに対して同等のプロパティ割り当てがある。
131131
132132これまでのコードでは、フィルターの使用を強制されている。 ユーザーが編集ボックスに空の値を指定した場合、レコードは表示されない。 おそらくこれは私たちが望んでいることではない。 空の値をテストし、それに応じてクエリを作成しよう。 最終的には次のような手順になるはずだ。
133133
134134``` pascal
135135procedure TForm1.Button1Click(Sender: TObject);
136136begin
137137 SQLQuery1.Close;
138138 // Firebird/Interbaseデータベースの接続設定
139139 // まだ接続していない場合にのみ必要:
140140 if not DBConnection.Connected then
141141 begin
142142 DBConnection.HostName := ServerName.Text;
143143 DBConnection.DatabaseName := DatabaseName.Text;
144144 DBConnection.Username := UserName.Text;
145145 DBConnection.Password := Password.Text;
146146 // これで接続が設定された。それを視覚的に示す。
147147 // 変更はもう行われない可能性がある
148148 ServerName.ReadOnly:=true;
149149 DatabaseName.ReadOnly:=true;
150150 UserName.ReadOnly:=true;
151151 Password.ReadOnly:=true;
152152 end;
153153 // すべてのレコードを表示するか、ユーザーがフィルター基準を指定した場合はフィルターする
154154 if Edit1.Text='' then
155155 SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';
156156 else
157157 begin
158158 SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';
159159 SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
160160 end;
161161 DBConnection.Connected:= True;
162162 SQLTransaction1.Active:= True;
163163 SQLQuery1.Open;
164164end;
165165```
166166
167167ここで、Edit1 を使用してフィルタリングを少し試す。 データベースに存在しない国を入力すると、空のグリッドが表示される。
168168
169169### エラー処理
170170
171171アプリケーションは実行されるはずだが、場合によっては問題が発生する可能性がある。 データベース、さらには組み込みデータベースもクラッシュする可能性があり (データベース サーバーがクラッシュした場合、ディスクがいっぱいになった場合、または単にバグが原因である場合など)、アプリケーションがハングしたままになる。
172172
173173したがって、データベース (実際には任意の外部プロセス) へのアクセスは、「常に」、try ... 例外および/または try ...finally 構造に統合される必要がある。 これにより、データベース エラーが確実に処理され、ユーザーが孤立することがなくなる。 このサンプル アプリケーションの基本的なルーチンは次のようになる。
174174
175175``` pascal
176176begin
177177 try
178178 SQLQuery1.Close;
179179 ...
180180 SQLQuery1.Open;
181181 except
182182 //一般的なデータベース エラーである EDatabaseErrorが必要だが、ここでは Firebird/Interbase を扱っているため、次のようになる:
183183 on E: EDatabaseError do
184184 begin
185185 MessageDlg('Error','A database error has occurred. Technical error message: ' + E.Message,mtError,[mbOK],0);
186186 Edit1.Text:='';
187187 end;
188188 end;
189189end;
190190```
191191
192192#### SQLite、PostgreSQL、その他のデータベース
193193
194194さらに詳細が必要な場合は、より汎用的な EDatabaseError を使用するか、使用可能な場合は独自の特殊な DatabaseError を使用できる。 例えば。 SQLite と FPC 2.6.1 以前の PostgreSQL ドライバーには特殊な E*DatabaseError がなく、EDatabaseError を使用する必要がある。 FPC (開発版)の PostgreSQL に EPQDatabaseError がある。
195195
196196## グリッドを使用したデータの編集
197197
198198### 編集
199199
200200これまで、グリッド内のデータを編集しようとしても、変更は保存されなかった。 これは、「SQLQuery1」が適切なタイミングでデータベース トランザクションに変更を送信するように指示されていないためだ。 これを修正し、データベースにトランザクションをコミットして、すべての変更が書き込まれるようにする必要がある。 このためには、次のようなコードを使用する。
201201
202202``` pascal
203203SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡す...
204204SQLTransaction1.cmmit; //...そしてトランザクションを使用してコミットする。
205205//SQLTransaction1.Active は false
206206```
207207
208208編集 (挿入、更新、削除) がデータベースに書き込まれることを確認したいとする。
209209
210210- ユーザーがフィルタリング基準を変更し、ボタンを押してデータベースにクエリを実行したとき
211211- フォームを閉じたとき
212212
213213これら 2 つのインスタンスで呼び出される、このために別のプロシージャを作成することは理にかなっている コードに移動し、ここに空の行を追加する。
214214
215215``` pascal
216216TForm1 = class(TForm)
217217 Button1: TButton;
218218 Datasource1: TDatasource;
219219 DBGrid1: TDBGrid;
220220 Edit1: TEdit;
221221 DBConnection: TIBConnection;
222222 SQLQuery1: TSQLQuery;
223223 SQLTransaction1: TSQLTransaction;
224224*****ここに空行を挿入****
225225 procedure Button1click(Sender: TObject);
226226 procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
227227 private
228228```
229229
230230次に、次のように入力する。
231231
232232``` pascal
233233 procedure SaveChanges;
234234```
235235
236236shift-ctrl-c (デフォルトの組み合わせ) を押すと、コード補完によって対応するプロシージャ本体が自動的に作成される。
237237
238238エラー処理を追加して、トランザクションがアクティブであることを確認する必要がある。このコードは、トランザクションがまだアクティブではないときに初めてボタンを押したときにも呼び出されることを覚えておくこと。ここで:
239239
240240``` pascal
241241procedure Tform1.SaveChanges;
242242// Saves edits done by user, if any.
243243begin
244244 try
245245 if SQLTransaction1.Active then
246246 // 開始されたトランザクション内にいる場合のみ;
247247 // それ以外の場合は、"Operation cannot be performed on an inactive dataset"というメッセージが表示される。
248248 begin
249249 SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡す...
250250 SQLTransaction1.Commit; //...そしてトランザクションを使用してコミットする。
251251 //SQLTransaction1.Active は false
252252 end;
253253 except
254254 on E: EDatabaseError do
255255 begin
256256 SQLTransaction1.Rollback;
257257 MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
258258 E.Message, mtError, [mbOK], 0);
259259 Edit1.Text := '';
260260 end;
261261 end;
262262end;
263263```
264264
265265次に、適切な時点でこのプロシージャを呼び出す必要がある。
266266
267267``` pascal
268268procedure Tform1.Button1click(Sender: TObject);
269269begin
270270 SaveChanges; //変更を保存しトランザクションをコミット
271271 try
272272 SQLQuery1.Close;
273273....
274274```
275275
276276そして:
277277
278278``` pascal
279279procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
280280begin
281281 SaveChanges; //変更を保存しトランザクションをコミット
282282 SQLQuery1.Close;
283283....
284284```
285285
286286次に、dbgrid で行われた編集がデータベースに保存されるかどうかをテストして確認する。
287287
288288### 主キー列の非表示
289289
290290多くの場合、自動採番/生成された主キーは参照整合性を維持することのみを目的としているため、ユーザーに表示されたくないことがある。 ユーザーがそれらを見た場合、数値を編集しようとしたり、数値が変わったり、数値にギャップがあるなどのことに腹を立てたりする可能性がある。
291291
292292この例では、CUST_NO が主キーで、コンテンツはトリガーとシーケンス/ジェネレーターを使用して Firebird によって自動生成される。 これは、CUST_NO を指定せずに新しいレコードを挿入できることを意味する。Firebird が自動的に作成する。
293293
294294CUST_NO を含めないように SQLQuery1.SQL.Text プロパティを変更することもできますが、これによりデータ編集時に問題が発生する。このような状況では、問題の行/レコードを一意に識別するために主キーが必要になる。
295295
296296したがって、テーブル内のすべての列/フィールドをクエリするトリックを使用するが、Button1Click プロシージャの最初のフィールド CUST_NO: がグリッドに表示されないようにして、次のようにコードを追加する:
297297
298298``` pascal
299299procedure Tform1.Button1click(Sender: TObject);
300300begin
301301...
302302 SQLQuery1.Open;
303303 // クエリの最初の列である主キー列を非表示にする
304304 // DBGrid が列を作成した後でのみこれを行うことができる
305305 DBGrid1.Columns[0].Visible:=false;
306306```
307307
308308再コンパイルし、主キー列が本当に非表示になっているかどうかを確認する。
309309
310310#### SQLite、その他のデータベース
311311
312312- その他のデータベース: 他の多くのデータベースは、自動生成されたフィールド コンテンツを提供するために「autonumber」または「autoinc」タイプのフィールドを使用します。 テーブル定義を変更して、それが機能するかどうかを確認すること。
313313- Sqlite: 整数の主キーを使用しているため、上記の例は SQLite でそのまま機能します。 詳細については、[ドキュメント](http://www.sqlite.org/autoinc.html) を参照のこと。
314314
315315### 新しいデータの挿入
316316
317317CUST_NO 情報なしで新しい行/レコードを挿入すると、次のエラー メッセージが表示されることに気づいたかもしれない: `Field CUST_NO is required, but not supplied`。 これは、前のセクションのように CUST_NO 列を非表示にした場合にも発生する。
318318
319319理由: Lazarus は CUST_NO が必要であると考えている。 これはそれほど奇妙ではない。これは主キーであり、データベース内の基になるテーブル定義で必須であると示されているからである。
320320
321321このフィールドが実際には必要ないことを Lazarus に指示できれば、空の値 (=NULL 値) をデータベースに渡すことができる。 幸いなことに、クエリのフィールド オブジェクトには、まさにそれを行う *Required* プロパティがある。
322322
323323コードを次のように変更する。
324324
325325``` pascal
326326 SQLQuery1.Open;
327327 {
328328 空白 (=NULL) CUST_NO 値を挿入しても問題が発生しないことを確認のこと。例:
329329 フィールド CUST_NO は必須だが、指定されていない
330330 Lazarus に、CUST_NO は主キーではあるが、新しいレコードを挿入するとき
331331 必須ではないことを伝える必要がある。
332332 }
333333 SQLQuery1.FieldByName('CUST_NO').Required:=false;
334334 // クエリの最初の列である主キー列を非表示にする。
335335 // DBGrid が列を作成した後でのみこれを行うことができる
336336 DBGrid1.Columns[0].Visible:=false;
337337```
338338
339339### データを削除する
340340
341341ユーザーにマウスを使用してこれを実行させることができる。 この機能については 1 行もコーディングする必要はない。
342342
343343「データ コントロール」タブで、「TDBNavigator」コンポーネントを選択し、フォームのグリッドの上にドロップする。
344344
345345ナビゲーターのリンク先を指定するには、オブジェクトインスペクタを使用して、ナビゲーターの *DataSource* プロパティを既存のデータソース ('DataSource1') に設定する。 これで、「DBNavigator」のボタンを使用してレコードを削除できるだけでなく、レコードを挿入したり、レコード内を移動したりすることもできる。 また、セル/フィールドを編集する場合、「キャンセル」ボタンを使用して編集をキャンセルすることができる。
346346
347-ユーザーが <span class="kbd">Delete</span> キーを使用してグリッド上の行を削除できるようにするには、uses 句に *LCLType* (これにはキー コードの定義が含まれる) を追加する。
347+ユーザーが `Delete` キーを使用してグリッド上の行を削除できるようにするには、uses 句に *LCLType* (これにはキー コードの定義が含まれる) を追加する。
348348
349349``` pascal
350350uses
351351 Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,
352352 Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;
353353```
354354
355-... 次に、グリッドの KeyUp イベントを処理する。このイベントは、グリッド内にある場合にキーが放されたときに発生する。 ただし、ユーザーがフィールドを編集していないことを確認する必要がある。ユーザーは、作業中のレコードではなく文字を削除するために <span class="kbd">Delete</span> キーを使用する可能性が高いためである。
355+... 次に、グリッドの KeyUp イベントを処理する。このイベントは、グリッド内にある場合にキーが放されたときに発生する。 ただし、ユーザーがフィールドを編集していないことを確認する必要がある。ユーザーは、作業中のレコードではなく文字を削除するために `Delete` キーを使用する可能性が高いためである。
356356
357357グリッドを選択し、イベントに移動して次のように OnKeyUp イベントを作成する。
358358
359359``` pascal
360360procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
361361 );
362362begin
363363 // del キーが押されたことを確認し、データを編集していない限り
364364 // それに応じて現在のレコードを削除する
365365 if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
366366 begin
367367 //... 現在のレコードを削除し、データベースに更新を適用する:
368368 SQLQuery1.Delete;
369369 SQLQuery1.ApplyUpdates;
370370 end;
371371end;
372372```
373373
374-> **Note:** デフォルトでは、TDBGrid プロパティ Options / dgDisableDelete は false に設定されている。これは、ユーザーが <span class="kbd">ctrl</span>-<span class="kbd">delete</span> キーの組み合わせを使用して任意のレコードを削除できることを意味する。 この動作は望ましくないかもしれない。
374+> **Note:** デフォルトでは、TDBGrid プロパティ Options / dgDisableDelete は false に設定されている。これは、ユーザーが `ctrl`-`delete` キーの組み合わせを使用して任意のレコードを削除できることを意味する。 この動作は望ましくないかもしれない。
375375
376376## 要約
377377
378378ここまで手順を進めてきたら、データベースからデータを取得し、フィルタリングし、グリッド内のデータを編集および削除できる。 コードは次のようになる:
379379
380380``` pascal
381381unit sqldbtutorial1unit;
382382
383383{$mode objfpc}{$H+}
384384
385385interface
386386
387387uses
388388 Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,
389389 Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;
390390type
391391
392392 { TForm1 }
393393
394394 TForm1 = class(TForm)
395395 Button1: TButton;
396396 DatabaseName: TEdit;
397397 Datasource1: TDatasource;
398398 DBGrid1: TDBGrid;
399399 Dbnavigator1: Tdbnavigator;
400400 Edit1: TEdit;
401401 Label2: Tlabel;
402402 Label3: Tlabel;
403403 Label4: Tlabel;
404404 Label5: Tlabel;
405405 Password: TEdit;
406406 UserName: TEdit;
407407 ServerName: TEdit;
408408 DBConnection: TIBConnection;
409409 Label1: TLabel;
410410 SQLQuery1: TSQLQuery;
411411 SQLTransaction1: TSQLTransaction;
412412 procedure SaveChanges;
413413 procedure Button1click(Sender: TObject);
414414 procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
415415 private
416416 { private declarations }
417417 public
418418 { public declarations }
419419 end;
420420
421421var
422422 Form1: TForm1;
423423
424424implementation
425425
426426{$R *.lfm}
427427
428428{ TForm1 }
429429
430430procedure Tform1.Savechanges;
431431// もしあれば、ユーザーによる編集を保存する。Saves edits done by user, if any.
432432begin
433433 try
434434 if SQLTransaction1.Active then
435435 // トランザクションを開始したときのみ
436436 // さもないと"Operation cannot be performed on an inactive dataset"にであることになる。
437437 begin
438438 SQLQuery1.ApplyUpdates; //ユーザーによる変更をデータベースに戻すPass user-generated changes back to database...
439439 SQLTransaction1.Commit; //... トランザクションを用いてコミット
440440 //SQLTransaction1.Active now is false
441441 end;
442442 except
443443 on E: EDatabaseError do
444444 begin
445445 SQLTransaction1.Rollback;
446446 MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
447447 E.Message, mtError, [mbOK], 0);
448448 Edit1.Text := '';
449449 end;
450450 end;
451451end;
452452
453453procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
454454 );
455455begin
456456 // データを編集しているとき以外に
457457 // Delキーが押され、それに応じて現在のレコードを消去する。
458458 if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
459459 begin
460460 //... delete current record and apply updates to db:
461461 SQLQuery1.Delete;
462462 SQLQuery1.ApplyUpdates;
463463 end;
464464end;
465465
466466procedure Tform1.Button1click(Sender: TObject);
467467begin
468468 SaveChanges; //変更を保存し、トランザクションをコミット
469469 try
470470 SQLQuery1.Close;
471471 //Firebird/Interbaseデータベースの接続設定
472472 //まだ、接続していないときにのみ必要である:
473473 if not DBConnection.Connected then
474474 begin
475475 DBConnection.HostName := ServerName.Text;
476476 DBConnection.DatabaseName := DatabaseName.Text;
477477 DBConnection.Username := UserName.Text;
478478 DBConnection.Password := Password.Text;
479479 // コネクションを張り、
480480 // 変更はもうないと視覚的に訴える
481481 ServerName.ReadOnly:=true;
482482 DatabaseName.ReadOnly:=true;
483483 UserName.ReadOnly:=true;
484484 Password.ReadOnly:=true;
485485 end;
486486 // すべてのレコードもしくはユーザーによって定義されたフィルタ定義で表示
487487 if Edit1.Text='' then
488488 SQLQuery1.SQL.Text := 'select * from CUSTOMER'
489489 else
490490 begin
491491 SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';
492492 SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
493493 end;
494494 DBConnection.Connected := True;
495495 SQLTransaction1.Active := True; //Starts a new transaction
496496 SQLQuery1.Open;
497497 {
498498 空(=NULL)値を挿入しても問題ない、即ち、エラーメッセージ "Field CUST_NO is required, but not supplied"
499499 が現れないようにすること。CUST_NOがプライマリキーであるときLazarusにそれを教える必要がある
500500 新しいレコードが挿入されるときには必要ない
501501 }
502502 SQLQuery1.FieldByName('CUST_NO').Required:=false;
503503 {
504504 クエリの最初のカラムであるプライマリキーを隠す。
505505 これはDBGridがカラムを生成するときに一度だけ行える
506506 }
507507 DBGrid1.Columns[0].Visible:=false;
508508 except
509509 // EDatabaseErrorは一般的なエラーだ;
510510 // 例えば、Firebird/Interbaseにおいては、EIBDatabaseErrorのような
511511 // データベースに特異なものを用いたほうがいいかもしれない
512512 on E: EDatabaseError do
513513 begin
514514 MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
515515 E.Message, mtError, [mbOK], 0);
516516 Edit1.Text := '';
517517 end;
518518 end;
519519end;
520520
521521procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
522522begin
523523 SaveChanges; //変更を保存し、トランザクションをコミットする
524524 SQLQuery1.Close;
525525 SQLTransaction1.Active := False;
526526 DBConnection.Connected := False;
527527end;
528528
529529end.
530530```
531531
532532## コード変更のない組み込みデータベース
533533
534534### Windows 上のFirebird
535535
536536Windows の Firebird ユーザーへのボーナス: このチュートリアルに従っている場合は (基本的な例しか実行していない場合でも)、埋め込まれた Firebird ライブラリの fbembed.dll の名前が fbclient.dll に変更されている。 これにより、Lazarus は通常の Firebird サーバ (別のマシンまたはローカルマシンのいずれか) に接続できるようになる。 ただし、サーバをセットアップせずに、employee.fdb データベースをアプリケーション ディレクトリにコピーし、アプリケーションを実行し、サーバ名 TEdit をクリアして、埋め込まれた Firebird を使用してデータベース ファイルに直接接続することもできる。
537537
538538これは、データベース アプリケーションをエンド ユーザーに展開したいが、サーバのインストールに手間をかけたくない (サーバがすでにインストールされているかどうか、バージョンが正しいかどうかを確認する、ユーザーにファイアウォールを確認させるなど) 場合に最適である。
539539
540540詳細については、[[Firebird embedded]] を参照されたい。
541541
5425422011 年 9 月: Free Pascal の最近の開発 (SVN) バージョンでは、FPC は最初に fbembed.dll をロードするので、これが機能するために fbclient.dll の名前を変更する必要はなくなった。
543543
544544### Linux/macOS/Unix 上の Firebird
545545
546546これを Linux/macOS で動作させる方法があるはずだ。 ヒントとリンクについては、[[Firebird|Firebirdを]]参照されたい。 Wiki の更新は大歓迎である。
547547
548548### SQLite
549549
550550SQLite は確かに組み込み機能を提供するが、その一方で、クライアント/サーバのセットアップは許可されていない。 上記のチュートリアルに従うと、データベース (SQLite と Firebird など) の切り替えがそれほど難しい作業ではないことがわかる。
551551
552552その他のデータベース データベースでも同様の機能が提供されている場合がある。 他のデータベース システム用のこの Wiki の更新も歓迎である。
553553
554554## 関連情報
555555
556556- [[SQLdb Tutorial1/ja]]: DB チュートリアルの第一の部分。データベースのデータを、どのように grid に表示させるかを学びます。
557557- [[SQLdb Tutorial2/ja]]: DB チュートリアルの第二の部分。データベースのデータの挿入や編集について学びます。
558558- [[SQLdb Tutorial3/ja]]: DB チュートリアルの第三の部分。複数のデータベースについてのプログラムやログインフォームの使い方を学びます。
559559- [[SQLdb Tutorial4/ja]]: DB チュートリアルの第四の部分。どのようにデータモジュールを用いるかを学びます。
560560- [[Lazarus Database Overview/ja]]: Lazarus がサポートしているデータベースについての情報。 データベースごとの記述へのリンクを含みます。
561561- [[SQLdb Package/ja]]: SQLdb パッケージについての情報
562562- [[SQLdb Programming Reference/ja]]: SQLdb データベースコンポーネントの入出力の概要
563563- [[SqlDBHowto/ja]]: SQLdb パッケージを用いることについての情報
564564- [[Working With TSQLQuery/ja]]: TSQLQuery についての情報
565565
566566---
567567*From the Free Pascal wiki, page "SQLdb Tutorial2/ja", as it stood on 2024-03-29 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).*

Back to history