Bonjour à tous.tes,
Je poste ici car j'ai un problème avec un TFDQuery.
Le ExecSQL plante sur une requête d'INSERT qui ne pose aucun problème dans le client SGBD
Est ce que ça vous parle ?
Bonjour à tous.tes,
Je poste ici car j'ai un problème avec un TFDQuery.
Le ExecSQL plante sur une requête d'INSERT qui ne pose aucun problème dans le client SGBD
Est ce que ça vous parle ?
Ce serait plus simple avec le code mais souvent ce sont des chaînes vides '' non converties en '''' sous Delphi.
Alors, dites moi si c'est bizarre que je trouve ça bizarre, mais chaque ExecSQL envoie le code dans le (try) except, alors que l'enregistrement est bien enregistré dans la base
Mais c'est peut-être moi qui déc...ne. J'aurais dû faire boulanger
Ah le pain aux olives
Toujours pas de code ?
Ah bonjour Andnotor, je n'avais pas vu ton précédent message.
Alors voici le type d'ordre qui est envoyé avec plus d'une centaine d'inserts au lieu de deux, mais chaque ordre limité à 1000 caractères.
Et je boucle sur environ 80 de ces ordres EXECUTE BLOCK .
Les lignes commencent à être insérées après environ 1500 échecs. Du coup, seuls environ 1600 enregistrements sont insérés.
Celui-ci que je mets en dur dans le Qry.SQL.Text pour tester, ne fonctionne pas. Il part en except. Alors que les inserts qu'ils contient fonctionnent.
Pourquoi arrive t-il à insérer des lignes si la syntaxe n'est pas bonne ? Et pourquoi n'arrive t-il pas à en insérer certaines, alors qu'ils fonctionnent un par un ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Qry.SQL.Text := 'EXECUTE BLOCK AS BEGIN ' + 'INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''1'',''nom'',''code'',0.04,''EUR''); 'INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''2'',''nom2'',''code2'',0.05,''EUR''); END;' ;
Voilà. Merci quand même
Ah ben, de toute façon il passe dans le Except :
Mais bon, j'ai fait tellement d'essais... Qu'il ne faut peut-être se fixer la-dessus.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 try ExecSQL; except Message d'erreur end;
Au final, le résultat est que certaines requêtes ne fonctionnent pas, alors que d'autres si. Alors que toutes, envoyées une par une fonctionnent parfaitement.
Donc oui, ça vient du EXECUTE BLOC mais quoi dans le EXECUTE BLOC, qui fonctionne parfois ?
Tu as peut-être un problème de terminateur ; le ; ne pouvant pas être utilisé comme terminateur de EXECUTE BLOCK et de son contenu.
Essaie ceci :
Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 Qry.SQL.Text := 'set term #;' + 'EXECUTE BLOCK AS BEGIN ' + 'INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''1'',''nom'',''code'',0.04,''EUR'');' + 'INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''2'',''nom2'',''code2'',0.05,''EUR'');' + 'END#' + 'set term ;#'; ;
J'ai déjà essayé SET TERM mais le FDQuery n'en veux pas. Je vais réessayer demain. Merci Andnotor
Bonjour,
Tout d'abord, un script de ce type (que des inserts dans une même table) pourrait être réglé de différentes manières
- en utilisant une/des transactions (j'ai l'impression que cette partie n'est jamais envisagée)
- en utilisant la technique des ARRAYDMLs (truc spécifique à Firedac)
Ça, j'aime bien, une requête paramétrée et hop. Moins bien, c'est un code "rapide" dans le sens où pour des données "réelles" il faut se passer de la boucle si facile
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 // code d'insertion "rapide" FDQuery1.SQL.Text := 'insert into nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (:p1, :p2, :p3,:p4,:p5)'; FDQuery1.Params.ArraySize := 100; // Attention à ça pour info ArraySize doit être <=2147483647 for i := 0 to 100-1 do begin FDQuery1.Params[0].AsIntegers[i] := i; FDQuery1.Params[1].AsStrings[i] := format('nom%d',[i]); FDQuery1.Params[2]..AsStrings[i] := format('code%d',[i]); FDQuery1.Params[3].AsFloats[i] := Random(10000)/100; FDQuery1.Params[4].AsStrings[i] := 'EUR'; end; FDQuery1.Execute(100, 0);
pour info pour toute version de Firebird >= 2.1 cela procède comme un EXECUTE BLOCK
- en utilisant FDScript au lieu de FDQuery (oui j'insiste on en a déjà longuement discuté sur le forum Firebird ici et là) à tel point que j'en déduis que ce EXECUTE BLOCK est une fixette !
Cela écrit, c'est loin d'être un joli code ! Ces histoires de doubles apostrophes, etc.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 // todo : gérer les erreurs FDTransaction.StartTransaction; with FDScript1 do begin SQLScripts.Clear; SQLScripts.Add; with SQLScripts[0].SQL do begin Add('INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''1'',''nom'',''code'',0.04,''EUR'')'); Add('INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''2'',''nom2'',''code2'',0.05,''EUR'');'); end; ValidateAll; // permet de chercher les erreurs ExecuteAll; // exécute end; FDTransaction.Commit;
Pour un EXECUTE BLOCK le texte du FDScript serait (pour CMDSEP voir cette page)
par exemple en utilisant un tmemo ou un TrichEdit comme conteneur du script
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 -- SET CMDSEP pas SET TERM pour tout SGBD -- SET TERM c'est Firebird utilisé par exemple dans flamerobin ou ISQL -- SET CMDSEP c'est le préprocessing de Firedac qui se charge du séparateur SET CMDSEP #; EXECUTE BLOCK AS BEGIN DELETE FROM TEST; INSERT INTO TEST (ID, NOM) VALUES (1,'nom'); INSERT INTO TEST (ID, NOM) VALUES (2,'nom2'); END# SET CMDSEP ;#
NB. le AUTOCOMMIT peut être désactivé ainsi directement dans le script
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 procedure TForm7.Button3Click(Sender: TObject); begin //try // FDTransaction1.Options.AutoCommit:=False; FDTransaction1.StartTransaction; try FDScript1.ExecuteScript(RichEdit1.Lines); FDTransaction1.Commit; except FDTransaction1.Rollback; end; //finally // FDTransaction1.Options.AutoCommit:=true; //end; end;
NB2. L'inconvénient de l'utilisation d'un texte d'un Tmemo (ou dans mon cas un TRichEdit) est que l'on ne peut valider le texte du script (validate) avant de l'exécuter, contrairement à l'utilisation d'un fichier Texte contenant le script
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 SET AUTOCOMMIT OFF; SET CMDSEP #; EXECUTE BLOCK AS BEGIN DELETE * FROM TEST; INSERT INTO TEST (ID, NOM) VALUES (1,'nom'); INSERT INTO TEST (ID, NOM) VALUES (2,'nom2'); END# SET CMDSEP ;#
NB3. Il est possible d'avoir des retours d'informations (voir page aide )
MVP Embarcadero
Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
SGBD : Firebird 2.5, 3, SQLite
générateurs États : FastReport, Rave, QuickReport
OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd
Non, ce modèle de code ne fonctionne pas. Il part en except et n'insert rien dans la base. Si j'insère les deux lignse manuellement, il n'y a pas de soucis. Pas de soucis non plus en block avec SET TERM dans FlameRobin.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 SET CMDSEP #; EXECUTE BLOCK AS BEGIN INSERT INTO TEST (ID, NOM) VALUES ('1','nom'); INSERT INTO TEST (ID, NOM) VALUES ('2','nom2'); END#
En règle général, je ne fais pas confiance aux composants non natifs. Je préfèrerai toujours passer par du SQL pur plutôt que par un composant. Déjà parce que si on connaît SQL, je ne vois pas l'intérêt d'utiliser des composants qui font interface entre nous et SQL
L'application ayant été développée en FireDac, je dois maintenant faire avec...
Oui, je confirme que ça devient une fixette Je veux savoir pourquoi ça ne marche pas même dans un cas particulièrement simple comme l'insert de deux lignes.
Il y a quelque chose qui ne lui plaît pas et j'aimerai savoir quoi.
J'ai vérifié ces diverses propositions (pour le code il s'agit d'utiliser FDScript pas un FDQuery)
D11.3 / firebird 3.0
FDScript est un composant Natif de Firedac autant que FDQuery donc je ne comprends pas trop la reflexion.je ne fais pas confiance aux composants non natifs
Pour moi, FDquery c'est pour une instruction SQL, FDScript pour n instructions
Pour info ce code
fonctionne
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 fdQuery1.SQL.Clear; fdquery1.SQL.Add('EXECUTE BLOCK AS BEGIN'); fdquery1.SQL.Add('DELETE FROM TEST;'); fdquery1.SQL.Add('INSERT INTO TEST (ID, NOM) VALUES (''1'',''nom'');'); fdquery1.SQL.Add('INSERT INTO TEST (ID, NOM) VALUES (''2'',''nom2'');'); fdquery1.SQL.Add('END'); try fdquery1.Transaction:=FDtransaction1; fdTransaction1.StartTransaction; try fdquery1.ExecSQL; FDTransaction1.Commit; except on e:Exception do begin showmessage(e.Message); FDTransaction1.Rollback; end; end; finally fdquery1.Transaction:=nil; end;
MVP Embarcadero
Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
SGBD : Firebird 2.5, 3, SQLite
générateurs États : FastReport, Rave, QuickReport
OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd
Je n'ai pas l'impression que la classe d'Exception ni le message, voire un code d'erreur n'aient été fourni !
Cela pourrait peut-être aidé ?
Le seul code fourni est même pas juste syntaxiquement en Delphi : https://www.developpez.net/forums/d2.../#post11946187
Donc on ne fait que répondre à des informations approximatives.
ce SQL.Text ne contient AUCUN retour charriot ? aucun + sLineBreak + ?
C'est à mon avis un problème car cela donne un SQL mal découpé.
Je suis de l'avis de préparer explicitement la requête avec des paramètres, binder dans une boucle et valider la transaction
Et si une valeur contient une quote, car là on a un exemple en dur mais en réalité, les valeurs sont-elles protégées contre l'injection-SQL ?
Enfin EXECUTE BLOCK est-ce spécifique à FireBird ?
je suppose que c'est comme cela que SergioMaster a deviné la base mais il aurait appréciable de le préciser dès le début, ainsi que la version
Et la modification du séparateur, c'est encore spécifique à FireBird, le parser interne de FireDac qui gère les paramètres par exemple, est-ce qu'il ne panique pas un peu ?il
lfaut différencier l'objet Query de l'objet Script, encore une fois le parser interne impacte le résultat
FDScript proposé par SergioMaster semble pertinent pour exécuter plusieurs bloc
Pour ma part, je sais que j'ai du ré-écrire souvent les objets Scripts de ODAC et MyDAC qui découpait très mal les blocs DML où est glissé des blocs DDL / DCL ou de bloc de procédure (BEGIN END)
Et comme SergioMaster le souligne, le FDQuery n'est-il pas influencé par les retours-charriot, la différence notable entre SQL.Text et SQL.Add (je recommande un SQL.BeginUpdate aussi pour éviter le parsage partiel)
Enfin pour ne pas avoir confiance, faut-il avoir la connaissance pour le faire soi-même.
Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
Attention Troll Méchant !
"Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
L'ignorance n'excuse pas la médiocrité !
L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
Il faut avoir le courage de se tromper et d'apprendre de ses erreurs
Voici mon code de façon un peu plus précise.
J'ai essayé avec # mais aussi avec ^ en me disant qu'il y en avait déjà dans la trame finale envoyée à SQL. Mais ça ne marche pas mieux.
J'ai essayé avec le prix cauté et non cauté.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 try Qry.SQL.Text := ('SET CMDSEP ^; EXECUTE BLOCK AS BEGIN '); Qry.SQL.Add('INSERT INTO nomtable(IDtable, NOM, CODE, PRIX, UNITE)'); Qry.SQL.Add(' VALUES (''1'',''nom'',''code'',''0.01'',''EUR'')'); Qry.SQL.Add('INSERT INTO nomtable(IDtable, NOM, CODE, PRIX, UNITE)'); Qry.SQL.Add(' VALUES (''2'',''nom2'',''code2'',''0.02'',''EUR'')'); Qry.SQL.Add(' END;^'); ExecSQL; except Inc(Echecs); end;
il ne manque pas le ; à la fin des INSERT ?
En MS SQL, que je pratique en ce moment, c'est inutile
Mais en FireBird, cela l'est-il ?
Tester donc le code https://www.developpez.net/forums/d2.../#post11946330
Il fonctionne chez SergioMaster, il serait bien de commencer par le début sans ce CMDSEP
ExecSQL il n'est pas sur Qry ?
Curieux, c'est le bon objet ?
laisser donc le Except remonter le type d'exception, c'est une information intéressante, logger en mode Debug là au moins si dans le code final de PROD c'est inhibé.
Si ce code est en dur, autant créer un fichier .SQL, créer une ressource et faire un TResourceStream pour charger le SQL, c'est pratique pour des scripts très long et on peut plus facielement prendre son SQL entre DElphi et l'outil du SGBD
Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
Attention Troll Méchant !
"Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
L'ignorance n'excuse pas la médiocrité !
L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
Il faut avoir le courage de se tromper et d'apprendre de ses erreurs
Oui
non mais par les questions qui avaient été posées dans le forum Firebird
non seul SET TERM est spécifique IB/Firebird, c'est pour cela que j'ai proposé CMDSEP en lieu et placeEt la modification du séparateur, c'est encore spécifique à FireBird,
MVP Embarcadero
Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
SGBD : Firebird 2.5, 3, SQLite
générateurs États : FastReport, Rave, QuickReport
OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd
Ce code est faux il fallait écrire
celui-ci #13 aussi
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 qry.SQL.Text := 'EXECUTE BLOCK AS BEGIN ' + 'INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''1'',''nom'',''code'',0.04,''EUR'');'+ 'INSERT INTO nomtable (NUM, NOM, CODE, PRIX, UNITE) VALUES (''2'',''nom2'',''code2'',0.05,''EUR'');'+ 'END';
il manque des ; et inutile de mettre SET CMDSEP
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 try Qry.SQL.Text := ('SET CMDSEP ^;EXECUTE BLOCK AS BEGIN '); Qry.SQL.Add('INSERT INTO nomtable(IDtable, NOM, CODE, PRIX, UNITE)'); Qry.SQL.Add(' VALUES (''1'',''nom'',''code'',''0.01'',''EUR'');'); Qry.SQL.Add('INSERT INTO nomtable(IDtable, NOM, CODE, PRIX, UNITE)'); Qry.SQL.Add(' VALUES (''2'',''nom2'',''code2'',''0.02'',''EUR'');'); Qry.SQL.Add(' END;^'); ExecSQL; except Inc(Echecs); end;
mais aussi les maitriser ce qui ne semble pas le cas, ces FDQuerys sont mal écritsEnvoyé par DoLiv
MVP Embarcadero
Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
SGBD : Firebird 2.5, 3, SQLite
générateurs États : FastReport, Rave, QuickReport
OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd
Les modifs dont tu parles ne sont que des erreurs de transcription.
Le code corrigé ne fonctionne pas mieux.
Je vais déjà essayer de le redévelopper en DBExpress avant de me lancer sur d'autres composants scripts...
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager