Sign in Join
Wiki copytemporary

SqlDBHowto/fr: what changed

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

OldNewLine
11Ce texte est conçu comme un 'comment-faire'. Je veux répondre à un nombre de question une par une, et expliquer comment vous pouvez utiliser les diverses classes. Toutes ces questions sont posées l'une après l'autre et forme une sorte de tutoriel.
22
33Je vais essayer de le dire de telle façon que le texte peut être utilisé pour Lazarus ainsi que FreePascal. Cependant, les exemples sont écrits pour FreePascal (c'est-à-dire qu'ils sont des applications de type console).
44
55## Où puis-je trouver la documentation officielle ?
66
77Veuillez voir la documentation officielle à la page [SQLDB documentation](http://www.freepascal.org/docs-html/fcl/sqldb/index.html).
88
99## Comment se connecter à un serveur de base de données ?
1010
1111SqlDB ne se connecte pas directement à un serveur de base de données mais utilise un client qui correspond au serveur de base de données employé. SqlDB envoie les commandes à la bibliothèque cliente ; la bibliothèque cliente se connecte au serveur de base de données et transfert les commandes. Ce qui veut dire que la bibliothèque cliente doit être installée pour faire la connection à la base de données. Sous Windows le client est souvent une .dll, sous Linux un .so et sous OS/X une .dylib.
1212
1313Quand la bibliothèque cliente est installée convenablement, vous pouvez vous connecter à la base de données en utilisant un composant TSQLConnection. Divers composants TSQLConnection sont disponibles pour les différents serveurs de bases de données (voir [[SQLdb Package/fr|SQLdb_Package]]) :
1414
1515- Firebird/Interbase: [[TIBConnection/fr|TIBConnection]]
1616- MS SQL Server: [[TMSSQLConnection/fr|TMSSQLConnection]] (disponible depuis FPC 2.6.1)
1717- MySQL v4.0: [[TMySQL40Connection/fr|TMySQL40Connection]]
1818- MySQL v4.1: [[TMySQL41Connection/fr|TMySQL41Connection]]
1919- MySQL v5.0: [[TMySQL50Connection/fr|TMySQL50Connection]]
2020- MySQL v5.1: [[TMySQL51Connection/fr|TMySQL51Connection]] (disponible depuis FPC version 2.5.1
2121- MySQL v5.5: [[TMySQL55Connection/fr|TMySQL55Connection]] (disponible depuis Lazarus 1.0.8/FPC version 2.6.2
2222- MySQL v5.6: [[TMySQL56Connection/fr|TMySQL56Connection]] (disponible dans Lazarus 1.2.4/FPC version 2.6.4
2323- ODBC: [[TODBCConnection/fr|TODBCConnection]] (voir [[ODBCConn/fr|ODBCConn/fr#TODBCConnection]])
2424- Oracle: [[TOracleConnection/fr|TOracleConnection]] (voir [[Oracle/fr|Oracle]])
2525- PostgreSQL: [[TPQConnection/fr|TPQConnection]] (voir [[postgres/fr|postgres/fr#SQLDB]])
2626- Sqlite3: [[TSQLite3Connection/fr|TSQLite3Connection]] (disponible depuis FPC version 2.2.2, voir [[SQLite/fr|SQLite/fr#Built-in_SQLDB]])
2727- Sybase ASE: [[TSybaseConnection/fr|TSybaseConnection]] (disponible depuis FPC 2.6.1, voir [[Lazarus Database Overview/fr|Lazarus et MSSQL/Sybase]])
2828
2929Note pour MySQL - Il y a plusieurs différences entre les versions de clients qui font que les connections ne peuvent être interchangées. Si une bibliothèque cliente version 4.1 est installée, vous devez utiliser un TMySQL41Connection. Ce n'est pas lié au serveur MySQL ; en utilisant une bibliothèque cliente MySQL 4.1, vous pouvez probablement vous connecter à un serveur MySQL 5.0 (voir la documentation MySQL concernant les combinaisons supportées).
3030
3131Bien que les détails diffèrent entre les les diverses bases de données, en général, vous aurez besoin de définir quatre propriétés pour vous connecter au serveur de base de données :
3232
3333- Le nom du serveur ou l'adresse IP
3434- Le nom de la base de données
3535- Le nom de connection
3636- Le mot de passe
3737
3838Quand ces propriétés sont définies, vous pouvez créer une connection avec la méthode 'open'. Si la connection échoue, une exception EDatabaseError est levée. Utilisez la propriété 'connected' pour savoir si la connection a été établie avec le serveur de base données. Utilisez la méthode 'close' pour mettre fin à la connection avec le serveur.
3939
4040``` pascal
4141Program ConnectDB;
4242
4343{$mode objfpc}{$H+}
4444
4545uses
4646 IBConnection;
4747
4848function CreateConnection: TIBConnection;
4949begin
5050 result := TIBConnection.Create(nil);
5151 result.Hostname := 'localhost';
5252 result.DatabaseName := '/opt/firebird/examples/employee.fdb';
5353 result.UserName := 'sysdba';
5454 result.Password := 'masterkey';
5555end;
5656
5757var
5858 AConnection : TIBConnection;
5959
6060begin
6161 AConnection := CreateConnection;
6262 AConnection.Open;
6363 if Aconnection.Connected then
6464 writeln('Successful connect!')
6565 else
6666 writeln('This is not possible, because if the connection failed, ' +
6767 'an exception should be raised, so this code would not ' +
6868 'be executed');
6969 AConnection.Close;
7070 AConnection.Free;
7171end.
7272```
7373
7474Si une exception est levée, lisez le message attentivement. Il se peut que le serveur ne soit pas en cours d'exécution, le nom de connection et/ou le mot de passe est incorrect ou le nom de base de données ou l'adresse IP sont mal orthographiés. Si le message d'erreur indique que la bibliothèque cliente n'est pas trouvée, alors il faut contrôler que le client est correctement installé. Souvent, le message d'erreur donne le nom du fichier recherché.
7575
7676## Comment exécuter des requêtes directes/créer une base de données ?
7777
7878SQlDB - le nom dit tout - fonctionne uniquement avec des serveurs de bases de données qui font usage de SQL. SQL signifie Langage Structuré de Requête (*Structured Query Language*), il est un langage développé pour permettre de travailler avec des bases de données relationnelles. Virtuellement chaque SGDBR (Système de Gestion de Bases de Données Relationnelles) a son propre dialecte, mais une grande partie des ordres SQL est la même pour tous les SGBDR.
7979
8080Dans FPC, il y a une différence entre :
8181
8282- des instructions qui retournent de l'information (un DataSet). Pour ceci, vous utiliserez un composant TSQLQuery ; voir #Comment lire de la donnée depuis une table ?.
8383- des instructions qui ne retournent pas d'information mais font quelque chose d'autre p.ex. mettre à jour des données. Pour ceci, vous pouvez aussi utiliser la méthode 'ExecuteDirect' de TSQLConnection (Vous pouvez également utiliser cette option si vous récupérez un jeu de données, mais que vous n'êtes pas intéressé par les résultats, par exemple dans une procédure stockée pouvant être sélectionnée).
8484
8585La plupart des SGBDR exécute des ordres SQL dans une transaction. Si vous voulez rendre les changements dans une transaction disponibles dans d'autres transactions, ou avoir ces changements disponibles après la fermeture de la transaction, alors vous devez faire un 'commit' de la transaction.
8686
8787Pour supporter les transactions, SqlDB contient un composant TSQLTransaction. Un ordre SQL qui est exécuté par SqlDB doit toujours être exécuté au sein d'une transaction, même si le SGBDR ne supporte pas les transactions. Aussi, il y a des SGBD qui supporte la transaction et pour lequel TSQLConnection ne supporte pas (encore) la transaction. Même là, vous devez employer le composant TSQLTransaction.
8888
8989Pour utiliser `TSQLConnection.ExecuteDirect` pour exécuter un ordre SQL, vous devez spécifier quelle 'transaction' doit être utilisée. A son tour, pour utiliser TSQLTransaction, vous devez spécifier quel composant TSQLConnection doit être utilisé.
9090
9191L'exemple suivant crée une table 'TBLNAMES' avec des champs 'NAME' et 'ID' et insère deux enregistrements. Cette fois en utilisant SQLite. Les ordres SQL employés ne sont pas expliqués. Pour plus d'information sur les ordres SQL, leur emploi et syntaxe, veuillez vous référer à la documentation du SGBDR. Remarquez que cet exemple ne tente pas d'intercepter les exceptions, ce qui est une mauvaise chose ! Regardez dans [Exceptions](https://www.freepascal.org/docs-html/current/ref/refch17.html#x226-24800017).
9292
9393``` pascal
9494program CreateTable;
9595{$mode objfpc} {$ifdef mswindows}{$apptype console}{$endif}
9696uses
9797 sqldb, sqlite3conn;
9898
9999var
100100 AConnection : TSQLite3Connection;
101101 ATransaction : TSQLTransaction;
102102
103103begin
104104 AConnection := TSQLite3Connection.Create(nil);
105105 AConnection.DatabaseName := 'test_dbase';
106106
107107 ATransaction := TSQLTransaction.Create(AConnection);
108108 AConnection.Transaction := ATransaction;
109109 AConnection.Open;
110110 ATransaction.StartTransaction;
111111 AConnection.ExecuteDirect('create table TBLNAMES (ID integer, NAME varchar(40));');
112112
113113 ATransaction.Commit;
114114
115115 ATransaction.StartTransaction;
116116 AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (1,''Name1'');');
117117 AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (2,''Name2'');');
118118 ATransaction.Commit;
119119 AConnection.Close;
120120 ATransaction.Free;
121121 AConnection.Free;
122122end
123123```
124124
125125## Comment lire de la donnée depuis une table ?
126126
127127Utilisez le composant TSQLQuery pour lire la donnée depuis une table. Un composant TSQLQuery doit être connecté à un composant TSQLConnection et à un composant TSQLTransaction pour réaliser sa tâche. La configuration de TSQLConnection et TSQLTransaction est discutée dans #Comment se connecter à un serveur de base de données ? et #Comment exécuter des requêtes directes/créer une base de données ?.
128128
129129Quand les TSQLConnection, TSQLTransaction et TSQLQuery sont connectés, alors TSQLQuery demande davantage de configuration pour fonctionner. TSQLQuery possède une propriété 'SQL' contenant un objet TStrings. La propriété TStrings contient un ordre SQL qui doit être exécuté. Si toutes les données de la table `tablename` doivent être lues, alors la propriété SQL doit contenir :
130130
131131``` sql
132132'SELECT * FROM tablename;'
133133```
134134
135135.
136136
137137Utilisez 'Open' pour lire la table du serveur et mettre les données dans le DataSet TSQLQuery. La donnée peut être accédée à travers TSQLQuery jusqu'à ce que la requête soit fermée en utilisant 'Close'.
138138
139139TSQLQuery est une sous-classe de TDataset. TDataset possède une collection de 'Fields' (champs) qui contiennent toutes les colonnes de la table. Le DataSet garde aussi la trace de l'enregistrement courant. Utilisez 'First', 'Next', 'Prior' et 'Last' pour changer l'enregistrement courant. 'Bof' retourne 'True' si le premier enregistrement est atteint et 'Eof' retourne 'True' si le dernier enregistrement est atteint. Pour lire la valeur d'un champ dans l'enregistrement courant, trouvez d'abord le bon objet 'TField' et alors utilisez 'AsString', AsInteger', etc.
140140
141141### Exemple : Lecture de donnée depuis une table
142142
143143Ci-dessous se trouve un exemple qui affiche toutes les valeurs de la table tel que cela est fait au dessus #Comment exécuter des requêtes directes/créer une base de données ?.
144144
145145``` pascal
146146Program ShowData;
147147
148148function CreateQuery(pConnection: TIBConnection; pTransaction: TSQLTransaction): TSQLQuery;
149149begin
150150 result := TSQLQuery.Create(nil);
151151 result.Database := pConnection;
152152 result.Transaction := pTransaction
153153end;
154154
155155var
156156 AConnection : TSQLConnection;
157157 ATransaction : TSQLTransaction;
158158 Query : TSQLQuery;
159159
160160begin
161161 AConnection := CreateConnection;
162162 ATransaction := CreateTransaction(AConnection);
163163 Query := CreateQuery(AConnection, ATransaction);
164164 Query.SQL.Text := 'select * from tblNames';
165165 AConnection.Open;
166166 Query.Open;
167167 while not Query.Eof do
168168 begin
169169 Writeln('ID: ', Query.FieldByName('ID').AsInteger, 'Name: ' +
170170 Query.FieldByName('Name').AsString);
171171 Query.Next;
172172 end;
173173 Query.Close;
174174 AConnection.Close;
175175 Query.Free;
176176 ATransaction.Free;
177177 AConnection.Free;
178178end.
179179```
180180
181181(le code du dessus n'est bien sûr pas tout à fait terminé. Il manque des blocs 'try...finally'. Il s'agit de montrer le code d'accès à la base de données, la finition est mise de côté.) Veuillez remarquer que 'TSQLTransaction.StartTransaction' n'est pas utilisé. Ce n'est pas nécessaire. Quand TSQLQuery est ouverte, l'ordre SQL est exécuté et si aucune transaction n'est disponible alors une transaction est automatiquement démarrée. Le développeur n'a pas besoin de démarrer une transaction explicitement. La même chose s'applique à la connection maintenue par TSQLConnection. La connection est ouverte au besoin, La ligne 'Aconnection.Open' n'est pas vraiment requise. Si un TSQLTransaction est détruit, un 'RollBack' automatique sera exécuté. **Des modifications de données contenues dans la transaction pourront être perdues.**
182182
183183### Pourquoi TSQLQuery.RecordCount retourne toujours 10 ?
184184
185185Pour compter les enregistrements dans un DataSet, utilisez la propriété '.RecordCount'. Pourtant, remarquez que '.RecordCount' montre le nombre d'enregistrements qui sont déjà chargés depuis le serveur. Pour des raisons de performance, SqlDB ne lit pas tous les enregistrements à l'ouverture du TSQLQuery par défaut, seulement les 10 premiers. Ce n'est que lorsque le onzième enregistrement est accédé que le prochain ensemble de 10 enregistrements sera chargé, etc. En utilisant '.Last', tous les enregistrements seront chargés.
186186
187187Quand vous voulez savoir le nombre effectif d'enregistrements sur le serveur, vous pouvez appeler '.Last' puis appeler '.RecordCount'.
188188
189189Une alternative est disponible. Le nombre d'enregistrements retourné par le serveur est définie par la propriété '.PacketRecords'. La valeur par défaut est 10, si vous la mettez à -1 alors tous les enregistrements seront chargés en une seule fois.
190190
191191Dans la version stable actuelle de FPC, '.RecordCount' ne prend pas en considération les filtres, i.e. montre le total non filtré.
192192
193193Si vous avez besoin du nombre exact d'enregistrement, il est mieux de demander directement le nombre d'enregistrements dans une autre requête SQL, mais vous devez faire cela dans la même transaction, car d'autres transaction ont pu modifier ce nombre dans l'entre-temps.
194194
195195### Lazarus
196196
197197Lazarus possède divers composants pour montrer les données d'un DataSet sur une fiche. A la place d'une boucle while et d'appels WriteLn comme ci-dessus, vous pouvez utiliser des composants pour montrer les données dans une table. Placez les bons composant TSQLConnection, TSQLTransaction et TSQLQuery sur une fiche, connectez-les et configurez-les convenablement. En plus, vous aurez besoin d'un TDataSource ; mettez dans la propriété 'TDatasource.Dataset' le composant TSQLQuery que vous utilisez.
198198
199199(**Remarque** ne définissez pas la propriété 'TSQLQuery.Datasource' par le composant TDatasource que vous utilisez. Cette propriété est réservée à la mise en place de realtion maître/détail entre tables - voir [[MasterDetail/fr|MasterDetail]]). Par la suite, vous pouvez poser un TDBGrid sur la fiche et définir la propriété 'DataSource' de la grille avec le composant TDataSource que vous avez ajouté auparavant.
200200
201201Pour voir si tout marche, mettez à 'True' la propriété 'Connected' du TSQLConnection dans l'EDI de Lazarus. L'EDI tentera de se connecter au serveur de base de données immédiatement. Si cela marche, mettez à 'True' la proriété 'TSQLQuery.Active'. Si tout est bon, vous verrez - dans l'EDI - toutes les données de la table immédiatement à l'écran.
202202
203203## Comment modifier de la donnée dans une table ?
204204
205205Pour modifier les données dans un enregistrement, les [[TDataSet/fr|TDataSet]] (duquel est dérivé TSQLQuery) doit être mis en mode édition. Pour ce faire, appelez l'une des méthodes '.Edit', '.Insert' ou '.Append'. Utilisez '.Edit' pour modifier les valeurs de l'enregistrement courant. Utilisez '.Insert' pour insérer un nouvel enregistrement avant l'enregistrement courant. Utilisez '.Append' pour ajouter un nouvel enregistrement en fin de la table. En mode Edit, vous pouvez changer les valeurs des champs grâce à la propriété 'Fields'. Utilisez la méthode '.Post' pour valider les nouvelles données, si les données sont valides, le mode Edit est abandonné. Si vous vous déplacez vers un autre enregistrement - par exemple en appelant '.Next' - et que le DataSet est en mode Edit, alors '.Post' est d'abord appelé. Utilisez '.Cancel' pour annuler tous les changements apportés depuis le dernier appel à '.Post' et quitter le mode Edit.
206206
207207``` pascal
208208Query.Edit;
209209Query.FieldByName('NAME').AsString := 'Edited name';
210210Query.Post;
211211```
212212
213213Ce qu'il y a au dessus n'est pas encore complet. TSQLQuery est dérivé de TBufDataset qui fait des mises à jour tamponnées (*buffered updates*). Les mises à jour tamponnées veulent dire qu'après l'appel à '.Post', les modifications sont visibles immédiatement dans l'ensemble de données mais pas envoyées au serveur de base de données. Il se passe que les modifications sont maintenues dans un journal des modifications. Quand la méthode '.ApplyUpdates' est appelée, tous les changements sont envoyés à la base de données. C'est à ce moment seulement que la base de données connaîtra les modifications. Les changements sont envoyés au serveur dans une transaction de TSQLTransaction. Assurez-vous de définir correctement la transaction avant d'appeler '.ApplyUpdates'. Après avoir appliquer les mises à jour, un commit doit être exécuté pour enregistrer les modifications sur le serveur de base de données.
214214
215215Ci-dessous est un exemple de modification de données dans une table, d'envoi les modifications et de commit de la transaction.
216216
217217``` pascal
218218Program EditData;
219219
220220var
221221 AConnection : TSQLConnection;
222222 ATransaction : TSQLTransaction;
223223 Query : TSQLQuery;
224224
225225begin
226226 AConnection := CreateConnection;
227227 ATransaction := CreateTransaction(AConnection);
228228 AConnection.Transaction := ATransaction;
229229 Query := CreateQuery(AConnection, ATransaction);
230230 Query.SQL.Text := 'select * from tblNames';
231231 Query.Open;
232232 Query.Edit;
233233 Query.FieldByName('NAME').AsString := 'Edited name';
234234 Query.Post;
235235 Query.UpdateMode := upWhereAll;
236236 Query.ApplyUpdates;
237237 ATransaction.Commit;
238238 Query.Free;
239239 ATransaction.Free;
240240 AConnection.Free;
241241end.
242242```
243243
244244Pour une discussion sur 'UpdateMode', continuer la lecture.
245245
246246## Comment SqlDB envoie les modifications aux serveur de base de données ?
247247
248248Dans l'exemple de code dans #Comment modifier de la donnée dans une table ?, vous trouverez la ligne :
249249
250250``` pascal
251251Query.UpdateMode := upWhereAll;
252252```
253253
254254Sans explication de ce que cela fait. La meilleure façon de savoir ce que cette ligne fait est de la laisser de côté. Si vous laissez de côté l'instruction et suivez ce Comment-faire précisément, alors vous recevrez ce message d'erreur :
255255
256-`No update query specified and failed to generate one. (No fields for inclusion in where statement found)`
256+```text
257+No update query specified and failed to generate one. (No fields for inclusion in where statement found)
258+```
257259
258260Pour comprendre ce qui n'a pas marché, vous devez comprendre comment les modifications sont envoyées au serveur. La seule façon d'obtenir des données dans un serveur SQL est d'exécuter des requêtes. SQL a trois types de requêtes pour trois différentes façons de manipuler un enregistrement. Pour créer un nouvel enregistrement, modifier ou supprimer un enregistrement, les ordres insert, update et delete sont exécutés respectivement. Un ordre de mise à jour peut être comme ce qui suit :
259261
260262``` sql
261263update TBLNAMES set NAME='Edited name' where ID=1;
262264```
263265
264266Pour envoyer le changement au serveur de base de données, SqlDB doit assembler une requête update. Pour ce faire, trois choses sont nécessaires :
265267
266268Le nom de la table
267269La nom de la table est récupéré par l'analyse de la requête de sélection, même si cela ne marche pas toujours.
268270
269271Clause `UPDATE` ou `INSERT`
270272Celle-ci contient les champs qui doivent être changés.
271273
272274Clause `WHERE`
273275Celle-ci contient les champs qui détermine quels enregistrements devraient être changés.
274276
275277Chaque champ (chaque *TField* dans *Fields*) possède une propriété ProviderFlags. Seuls les champs avec **pfInUpdate** dans *ProviderFlags* seront utilisés dans la clause update ou insert d'une requête. Par défaut, *pfInUpdate* est mis pour tous les champs dans leur proriété *ProviderFlags*.
276278
277279Le choix des champs utilisés dans la clause `WHERE` dépend de la propriété *UpdateMode* de la requête et de la propriété *ProviderFlags* des champs. Les champs avec *pfInkey* dans leur *ProviderFlags* sont toujours utilisés dans la clause `WHERE`. Un champ aura le drapeau *pfInKey* défini automatiquement si le champ fait partie de la clé primaire de la table et 'TSQLQuery.UsePrimaryKeyAsKey' retourne 'True'.
278280
279281La valeur par défaut de *UpdateMode* de la requête est *upWhereKeyOnly*. Dans le mode update, seuls les champs avec *pfInkey* dans leur propriété *ProviderFlags* sont utilisés dans la clause `WHERE`. Si aucun des champs n'a de drapeau *pfInKey* mis, alors aucun champ n'est disponible pour la clause `WHERE` et le message d'erreur du début de la section sera retourné. Vous pouvez résoudre ce problème en :
280282
281283- En ajoutant une clé primaire à la table et mettre *TSQLQuery.UsePrimaryKeyAsKey* à 'True', ou
282284- en définissant le drapeau *pfInkey* pour un ou plusieurs champs dans le code.
283285
284286La propriété **UpdateMode** connaît deux autres valeurs. 'upWhereAll' peut être utilisée pour ajouter tous les champs avec le drapeau 'pfInWhere' mis à la clause `WHERE`. Par défaut, tous les champs ont ce drapeau mis. 'upWhereChanged' peut être utilisé pour ceux des champs qui ont le drapeau 'pfInWhere' mis et dont la valeur a été changée dans l'enregistrement courant.
285287
286288## Comment exécuter une requête en utilisant TSQLQuery ?
287289
288290À côté des instructions qui renvoient un DataSet (voir #Comment lire de la donnée depuis une table ?, SQL a des ordres qui ne retournent pas de donnée. P.ex., les ordres `INSERT`, `UPDATE` et `DELETE`. Ces ordres peuvent être exécutés en utilisant *TSQLConnection.ExecuteDirect*, mais TSQLQuery peut être aussi utilisé. Si vous n'attendez pas de donnée en retour, utilisez *TSQLQuery.ExecSQL* au lieu de *TSQLQuery.Open*. Comme indiqué précédemment, utilisez *TSQLQuery.Open* pour ouvrir le DataSet retourné par l'ordre SQL.
289291
290292La procédure suivante crée une table et insère deux enregistrements en utilisant TSQLQuery.
291293
292294``` pascal
293295procedure CreateTable;
294296
295297var
296298 Query : TSQLQuery;
297299
298300begin
299301 Query := CreateQuery(AConnection, ATransaction);
300302 Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
301303 Query.ExecSQL;
302304
303305 Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (1,''Name1'');';
304306 Query.ExecSQL;
305307
306308 Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (2,''Name2'');';
307309 Query.ExecSQL;
308310
309311 Query.Close;
310312 Query.Free;
311313end;
312314```
313315
314316## Comment utiliser des paramètres dans une requête ?
315317
316318Dans l'exemple de code de #Comment exécuter une requête en utilisant TSQLQuery ?, la même requête est utilisée deux fois, seules les valeurs à insérer diffèrent. Une meilleure façon pour faire cela consiste à utiliser des paramètres dans la requête.
317319
318320La syntaxe des paramètres dans les requêtes est différente selon le SGBDR, mais les différences sont traitées par TSQLQuery. Remplacez les valeurs dans la requête avec un caractère deux-points suivi du nom du paramètre que vous voulez utiliser. Par exemples :
319321
320322``` pascal
321323Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';
322324```
323325
324326Cette requête créera deux paramètres : 'ID' et 'NAME'. Pour déterminer les paramètres, la requête est analysée au moment où le texte de *TSQLQuery.SQL* est affecté ou modifié. Tous les paramètres existants seront supprimés et les nouveaux paramètres seront ajoutés à la propriété 'TSQLQuery.Params'. L'affectation d'une valeur à un paramètre est similaire à l'affectation d'un champ dans un DataSet :
325327
326328``` pascal
327329Query.Params.ParamByName('Name').AsString := 'Name1';
328330```
329331
330332Vous ne pouvez pas savoir depuis la requête quel type de donnée doit être stocké dans le paramètre. Le type de donnée est déterminé au moment où une valeur est en premier affectée à un paramètre. En affectant une valeur en utilisant '.AsString', le paramètre est affecté du type 'ftString'. Vous pouvez déterminer le type de donnée directement en définissant la propriété 'DataType'. Si un type de donnée incorrect est affecté au paramètre alors des problèmes surviendront lors de l'ouverture ou de l'exécution de la requête. Voir [[Database field type/fr|Type de champ de base de données]] pour plus d'information sur les types de donnée.
331333
332334### Requête de sélection
333335
334336Un exemple de requête de sélection avec des paramètres changera quelque chose comme ceci :
335337
336338``` pascal
337339 Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = '''+Edit1.Text+''' ORDER BY NAME ';
338340```
339341
340342en quelque chose comme cela :
341343
342344``` pascal
343345 Query.SQL.Text := 'select ID,NAME from TBLNAMES where NAME = :NAMEPARAM ORDER BY NAME ';
344346 Query.Params.ParamByName('NAMEPARAM').AsString := Edit1.Text;
345347```
346348
347349### Exemple
348350
349351L'exemple suivant crée la même table que l'exemple précédent, mais maintenant des paramètres sont utilisés :
350352
351353``` pascal
352354procedure CreateTableUsingParameters;
353355
354356var
355357 Query : TSQLQuery;
356358
357359begin
358360 Query := CreateQuery(AConnection, ATransaction);
359361 Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
360362 Query.ExecSQL;
361363
362364 Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';
363365 Query.Prepare;
364366
365367 Query.Params.ParamByName('ID').AsInteger := 1;
366368 Query.Params.ParamByName('NAME').AsString := 'Name1';
367369 Query.ExecSQL;
368370
369371 Query.Params.ParamByName('ID').AsInteger := 2;
370372 Query.Params.ParamByName('NAME').AsString := 'Name2';
371373 Query.ExecSQL;
372374
373375 //Query.UnPrepare; // no need to call this; should be called by Query.Close
374376 Query.Close;
375377 Query.Free;
376378end;
377379```
378380
379381Remarquez que cet exemple demande plus de code que l'exemple sans paramètre. Alors, à quoi sert l'utilisation de paramètres?
380382
381383La vitesse est une des raisons. L'exemple avec des paramètres est plus rapide, parce que le serveur de base de donnée analyse la requête une seule fois (dans l'instruction '.Prepare' ou à la première exécution). Une autre raison pour employer les instructions préparées est la prévention des [injections SQL](https://fr.wikipedia.org/wiki/Injection_SQL) (voir aussi [[Secure programming/fr|Programmation sécurisée]]).
382384
383385Finalement, dans certains cas, ils simplifient le codage.
384386
385387## Dépannage : Journalisation par TSQLConnection
386388
387389Vous pouvez laisser un journal TSQLConnection à ce qu'il fait. Cela peut être pratique pour voir ce que votre programme Lazarus envoie à la base de données exactement, pour déboguer les composants de base de données eux-mêmes et peut-être pour optimiser vos requêtes.\
388390NB : Si vous utilisez des ordres préparés/requêtes paramétrées (vois la section du dessus), les paramètres sont souvent envoyées en binaire par le descendant de TSQLConnection (p.ex. TIBConnection), donc vous ne pouvez juste copier/coller le SQL journalisé dans un outil d'interrogation de la base de données. Indépendamment, la journalisation de la connection peut donner beaucoup d'indication sur ce que le programme fait.
389391
390392Les alternatives sont :
391393
3923941. vous pouvez utiliser le débogueur pour passer le code de base données si vous avez construit FPC (et Lazarus) avec le débogage activé.
3933952. si vous utilisez les pilotes ODBC (au moins sous Windows), vous pourrez activer la sortie tracelog depuis le panneau de contrôle ODBC.
3943963. plusieurs SGBD vous permettent de contrôler tous les ordres envoyés vers lui depuis une adresse IP/une connection.
395397
396398Si vous utilisez la jouranlisation TSQLConnection, deux choses sont requises :
397399
3984001. indiquer quels sont les types d'événement que TSQLConnection doit journaliser.
3994012. associer TSQLConnection à une fonction qui reçoit les événements et les traite (les enregistre dans un fichier, les affiche à l'écran, etc.).
400402
401403Cette fonction doit être du type TDBLogNotifyEvent (voir sqldb.pp), donc elle doit avoir la signature :
402404
403405``` pascal
404406TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;
405407```
406408
407409### FPC (ou : la façon manuelle)
408410
409411Un extrait de code illustre ceci :
410412
411413``` pascal
412414uses
413415...
414416TSQLConnection, //or a child object like TIBConnection, TMSSQLConnection
415417...
416418var
417419type
418420 TMyApplication = class(TCustomApplication); //this is our application that uses the connection
419421...
420422 private
421423 // This example stores the logged events in this stringlist:
422424 FConnectionLog: TStringList;
423425...
424426 protected
425427 // This procedure will receive the events that are logged by the connection:
426428 procedure GetLogEvent(Sender: TSQLConnection; EventType: TDBEventType; Const Msg : String);
427429...
428430 procedure TMyApplication.GetLogEvent(Sender: TSQLConnection;
429431 EventType: TDBEventType; const Msg: String);
430432 // The procedure is called by TSQLConnection and saves the received log messages
431433 // in the FConnectionLog stringlist
432434 var
433435 Source: string;
434436 begin
435437 // Nicely right aligned...
436438 case EventType of
437439 detCustom: Source:='Custom: ';
438440 detPrepare: Source:='Prepare: ';
439441 detExecute: Source:='Execute: ';
440442 detFetch: Source:='Fetch: ';
441443 detCommit: Source:='Commit: ';
442444 detRollBack: Source:='Rollback:';
443445 else Source:='Unknown event. Please fix program code.';
444446 end;
445447 FConnectionLog.Add(Source + ' ' + Msg);
446448 end;
447449
448450...
449451 // We do need to tell our TSQLConnection what to log:
450452 FConnection.LogEvents:=LogAllEvents; //= [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack]
451453 // ... and to which procedure the connection should send the events:
452454 FConnection.OnLog:=@Self.GetLogEvent;
453455...
454456 // now we can use the connection and the FConnectionLog stringlist will fill with log messages.
455457```
456458
457459Vous pouvez aussi utiliser GlobalDBLogHook de TSQLConnection au lieu de journaliser depuis de multiples connections.
458460
459461### Lazarus (ou : la manière rapide)
460462
461463Au final, la description du dessus est la manière FPC de procéder comme annoncé dans l'introduction ; si vous utilisez Lazarus, une façon plus rapide est d'affecter le gestionnaire d'événement dans l'événement OnLog de TSQLConnection.
462464
463465## Voir aussi
464466
465467- [[SQLdb Tutorial0/fr|SQLdb Tutorial0]] : Instructions pour configurer les tables et les données d'exemple pour la série de tutoriels.
466468- [[SQLdb Tutorial1/fr|SQLdb Tutorial1]] : 1re partie de la série de tutoriels sur les bases de données, montrant comment configurer un grid pour afficher les données.
467469- [[SQLdb Tutorial2/fr|SQLdb Tutorial2]] : 2e partie de la série de tutoriels, montrant l'édition, l'insertion, etc.
468470- [[SQLdb Tutorial3/fr|SQLdb Tutorial3]] : 3e partie de la série de tutoriels, montrant comment développer pour des bases de données multiples et utiliser une form de login.
469471- [[SQLdb Tutorial4/fr|SQLdb Tutorial4]] : 4e partie de la série de tutoriels, montrant comment utiliser les data modules.
470472- [[Lazarus Database Overview/fr|Vue d'ensemble des bases de données pour Lazarus]] : Information sur les bases de données supportées par Lazarus. Redirige vers des notes spécifiques à certaines bases de données.
471473- [[SQLdb Package/fr|Paquet SQLdb]] : Information sur le paquetage SQLdb.
472474- [[SQLdb Programming Reference/fr|Référence de programmation SQLdb]] : Une vue d'ensemble de l'interaction entre les composants de bases de données SQLdb.
473475- [[SqlDBHowto/fr|SqlDBHowto]] : Information sur l'utilisation du paquet SQLdb.
474476- [[Working With TSQLQuery/fr|Travailler avec TSQLQuery]] : Informations sur TSQLQuery.
475477
476478---
477479*From the Free Pascal wiki, page "SqlDBHowto/fr", as it stood on 2020-02-27 after a change by Trev, 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