Comment tester syntaxe SQL [Résolu]

mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 14 août 2008 à 17:39 - Dernière réponse : AGILOGMAIL 5 Messages postés mercredi 2 juillet 2008Date d'inscription 15 mars 2010 Dernière intervention
- 2 sept. 2008 à 10:00
Bonjour,
j'aimerais savoir si l'on pouvait tester une syntaxe SQL avec Delphi.
Vous me direz que je pourrais mettre ma requête dans un TQuery, et tenter un open dans un try/except (et donc si dans l'except, syntaxe incorrecte, sous condition que le TQuery a toutes ses propriétés en bonnes et dues formes mais ça c'est bon)...

Seulement, ma requête est vraiment, vraiment super grosse, et elle prend entre 10 et 15 minutes à s'exécuter. Donc si dans la boucle try/except on fait cet "open"... l'utilisateur a autre chose à faire qu'attendre son booléen

C'est certainement un truc super classique, mais j'ai pas trouvé grand chose sur google pour faire ce genre de choses depuis delphi.

Je lance donc un appel à vos avis éclairés.

Merci
Afficher la suite 

Votre réponse

14 réponses

AGILOGMAIL 5 Messages postés mercredi 2 juillet 2008Date d'inscription 15 mars 2010 Dernière intervention - 2 sept. 2008 à 00:09
+3
Utile
Salut Mengele,


 


ajoute juste après toon 1er Where


( 0 = 1) AND ( ton code )


de cette façon l'évaluation sera faite rapidement


si ça plante ça te dira pas où mais au moins tu le sauras.


passe sous D7 au minimum... ça va te changer !!!






rien de sert de courir, il faut partir à point.
Certes, mais il faut partir.
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de AGILOGMAIL
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 14 août 2008 à 19:28
0
Utile
bonsoir,
Je pige pas..
Si ta requête est bonne, elle marche tout le temps..
?

cantador
Commenter la réponse de cs_cantador
mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 14 août 2008 à 20:06
0
Utile
salut,
non en fait, je génère la requête par programme. Et il reste encore quelques rares cas particuliers de *@!#~ qui font qu'il puisse manquer, ou y avoir en trop, une ou deux parenthèses (mais c'est très rare).

Comme je l'ai dit, la requête tient sur beaucoup de lignes (une bonne 50aine, voire plus). Et j'ai pas envie de faire un Open et de faire poireauter l'utilisateur pendant 25 minutes à la fermeture de la Form, juste pour lui confirmer que la requête sql générée est syntaxiquement correcte (90% des fois en plus).

Sachant qu'une vérif de syntaxe prend une fraction de secondes, même pour 50 lignes... ça serait bien de pouvoir passer par ça quoi , càd fair un truc du genre piloter mon sql server, mais à la place de piloter un clic sur le "!" de Exécuter, cliquer sur le "sql" de vérification syntaxique.

merci cantador.
Commenter la réponse de mengele
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 14 août 2008 à 22:44
0
Utile
mouais..mais dans ce cas, tu vas être obligé de cerner la zone qui pose problème et d'envisager tous les cas de figure qui peuvent se présenter.
Bref parser le morceau de chaîne SQL.
et mettre en place tous les tests..
Je m'avance un peu mais c'est peut-être des zones de paramétages qui coincent de temps en temps..

cantador
Commenter la réponse de cs_cantador
mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 15 août 2008 à 00:07
0
Utile
Oula, faire un parser pour des requêtes de plus de 50 lignes...
S'il s'agissait que de vérifier que le nombre de parenthèses ouvrantes = nb parenthèses fermantes... mais le problème est plus compliqué évidemment. Pour vérifier que toutes les parenthèses se ferment et s'ouvrent exactement au bon endroit, faudra se lever de bonne heure...
Et puis ça serait dommage de faire ce travail, alors que le SGBD le fait très bien, très efficacement et très rapidement.

merci quand même cantador.

Je vais attendre, peut-être que quelqu'un qui a déjà piloté ce genre de trucs passera sur mon post.

J'ai tenté un "open" dans un thread, que je tue au bout d'une tempo maxi. C'est pas terrible, mais au pire des cas si j'ai pas de réponses, je me tiendrai à ça.

Merci
Commenter la réponse de mengele
cs_cantador 4996 Messages postés dimanche 26 février 2006Date d'inscription 27 mars 2018 Dernière intervention - 15 août 2008 à 11:58
0
Utile
 et elle prend entre 10 et 15 minutes à s'exécuter.
je trouve quand même ce temps assez surprenant..

En fouillant dans mes archives, j'ai retrouvé un truc similaire que j'avais fait il y a longtemps mais certainement plus simple que ton cas de figure :
le principe était le suivant :
il s'agissait d'un SELECT :
tout le corps principal était figé, seul la clause WHERE était paramétrable et se modifiait selon les choix de l'utilisateur.

comme je vais m'absenter un bon moment, je te conseille de reposer ta question
sur le forum en demandant aux admins de détruire ce post.

@+

cantador
Commenter la réponse de cs_cantador
mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 15 août 2008 à 14:44
0
Utile
Salut,
ben moi c'est pareil, ma requête c'est un select, avec des jointures sur environ 20 tables (pour 50 lignes de requête). Je crée le contenu de mon where dans "MaReq" en fonction de ce que l'utilisateur a choisi dans la fiche.

Puis tout à la fin je fais un :
MaReq := 'Select T0.Champ from Table T0 Where (' + MaReq + ')';

Toutes les parenthèses, jointures et ordres des opérations OR/AND sont à présent respectées. J'ai pris la patience de vérifier à la main toutes les positions des parenthèses et des jointures et intersections.
Ma requête est juste. N'empêche qu'elle prend du temps quoi. Vu que c'est intersections et jointures une 20aine de fois sur la même table "Table" que je nomme chaque fois "Tn" (n integer), et que la table fait dans les 200 000 lignes.

Merci quand même.

Du coup, j'ai pas le choix, je vais devoir me contenter de mon thread.
Même si à présent la syntaxe est juste à 99% des fois. Le 1% étant atteint pour un rare cas particulier qui ne viendrait jamais à l'esprit de l'utilisateur, à moins d'avoir l'esprit très tordu :D

PS : le post reste ouvert, si vous avez des suggestions, même si elles viennent tard, c'est pas grave n'hésitez pas, que dis-je... n'hésitez plus
Commenter la réponse de mengele
cs_Delphiprog 4580 Messages postés samedi 19 janvier 2002Date d'inscription 9 janvier 2013 Dernière intervention - 17 août 2008 à 19:18
0
Utile
Salut,

Il serait intéressant de se pencher sur la classe TExprParser définie dans DbCommon.pas (source/vcl/DBCommon.pas). Mais, pour se faciliter davantage la tâche, on peut utiliser l'unité écrite par vlads et disponible sur sourceforge.net dans l'unité ExprParser.pas, dossier "units". C'est très simple puisque seule la fonction eval (function eval(str: WideString): boolean;) a besoin d'être appelée.
Je n'ai pas testé cette unité mais il me semble qu'elle correspond à ce que tu cherches.
Si tu veux voir à quoi ça ressemble avant de télécharger les 11 Mo, c'est http://mp3bookhelper.sourceforge.net/MP3BookHelper_v2.3.4_src.tar.gz&cs_f=Units/ExprParser.pas' target='_blank'>iciqu'il faut cliquer.

May Delphi be with you !
<hr color="#008000" />Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
Commenter la réponse de cs_Delphiprog
mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 18 août 2008 à 10:30
0
Utile
Salut,

Merci pour ta recherche DelphiProg.

Je suis sous Delphi4, et même, et je ne sais pour quelle raison l'unité ExprParser.pas ne veut pas compiler.

Fameuse erreur : '"Erreur fatale ExprParser.pas (1) : Ligne trop longue(plus de1023 caractères)"

J'ai essayé de résoudre le problème en enlevant petit à petit des parties du codemais je n'ai pas réussi à voir d'où venait l'erreur.
Je sais que c'est un message d'erreur qui m'a déjà fait abandonné des projets, donc ce coup-ci après 1h30 d'essai de le faire compiler inclus dans mon projet, j'abandonne.
Tant pis :(

J'arrive au bout de mon stage et j'ai pas le temps de me concentrer sur ce problème qui n'a pas lieu d'en être un :(

Merci quand même.
Commenter la réponse de mengele
cs_Delphiprog 4580 Messages postés samedi 19 janvier 2002Date d'inscription 9 janvier 2013 Dernière intervention - 18 août 2008 à 11:17
0
Utile
Et en utilisant le copier/coller ?{ $RCSfile: ExprParser.pas,v $ $Revision: 1.1 $ $Date: 2004/05/14 19:42:34 $ $Author: vlads $ }{ }{ ================================================================================== }{ }{ This file is part of MP3BookHelper, http://mp3bookhelper.sourceforge.net/ }{ See readme.txt and license.txt for details. }{ (c) Copyright 2002 - Vlad Skarzhevskyy & co }{ }{ This program is free software; you can redistribute it and/or modify it under }{ the terms of the GNU General Public License as published by the Free Software }{ Foundation; either version 2 of the License, or (at your option) any later }{ version. }{ }{ This program is distributed in the hope that it will be useful, but WITHOUT ANY }{ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A }{ PARTICULAR PURPOSE. See the GNU General Public License for more details. }{ }{ The GNU GPL can be found at: http://www.gnu.org/copyleft/gpl.html }{ }{ ================================================================================== }{$INCLUDE versions.inc}unit ExprParser;interfaceuses Contnrs;type TExprParser = class public value : WideString; ErrorMessage: WideString; constructor Create(); destructor Destroy; override; function eval(str: WideString): boolean; end;{$DEFINE TESTING_PARSER}var debugText : WideString;implementationuses SysUtils;const NUMBERS = [WideChar('0')..WideChar('9')]; LETTERS = [WideChar('a')..WideChar('z'), WideChar('A')..WideChar('Z'), WideChar('_')]; LETTERS_NUMBERS = [WideChar('0')..WideChar('9'), WideChar('a')..WideChar('z'), WideChar('A')..WideChar('Z'), WideChar('_')]; OPERATORS = [WideChar('+'), WideChar('-'), WideChar('/'), WideChar('*'), WideChar('=')];type EToken = (tkNA, tkEOF, tkError, tkLParen, tkRParen, tkComa, tkOperator, tkIdentifier, tkNumber, tkInteger, tkString); ELex = class public token: EToken; chr: Char; str: WideString; pos: integer; constructor Create(token: EToken; pos: integer); overload; constructor Create(token: EToken; str: WideString; pos: integer); overload; constructor Create(token: EToken; chr: WideChar; pos: integer); overload; function debug(): WideString; end; EScan = class(TObjectList) private function GetItem(Index: Integer): ELex; public ErrorMessage: WideString; constructor Create(); destructor Destroy; override; property Items[Index: Integer]: ELex read GetItem; default; function pars(str: WideString): boolean; procedure debugPrint(); end; EVariant = variant; { EVariant = class value: variant; constructor Create(int: Integer); overload; constructor Create(str: WideString); overload; function asString(): WideString; end; } ENode = class function eval(): EVariant; virtual; abstract; end; ParserException = class(Exception) public constructor Create(const Msg: string; lex: ELex); overload; constructor Create(const E: Exception); overload; end; ENodeCValue = class (ENode) public cvalue : ELex; constructor Create(cvalue: ELex); function eval(): EVariant; override; end; ENodeVariable = class (ENode) public lex : ELex; constructor Create(lex: ELex); function eval(): EVariant; override; end; ENodeUnary = class (ENode) public operator: ELex; rightNode: ENode; constructor Create(operator: ELex; rightNode: ENode); destructor Destroy; override; function eval(): EVariant; override; end; ENodeBin = class (ENode) public operator: ELex; lefNode, rightNode: ENode; constructor Create(operator: ELex; lefNode, rightNode: ENode); destructor Destroy; override; function eval(): EVariant; override; end; ENodeFunction = class (ENode) public func: ELex; args: TObjectList; constructor Create(func: ELex); destructor Destroy; override; procedure arg(Node: ENode); function eval(): EVariant; override; end; EParser = class public scan: EScan; scan_idx : integer; root: ENode; ErrorMessage: WideString; value: EVariant; constructor Create(); destructor Destroy; override; function pars(): boolean; function execute(): boolean; function Expr(): ENode; function Term(): ENode; function Factor(): ENode; function LexC(): ELex; function LexLook(look_ahead : integer = 1): ELex; procedure LexAcept(); end;var ELexEOF: ELex;procedure DebugMessage(msg: WideString);begin debugText := debugText + msg + sLineBreak;end;{ ELex }constructor ELex.Create(token: EToken; pos: integer);begin self.token := token; self.pos := pos;end;constructor ELex.Create(token: EToken; str: WideString; pos: integer);begin self.token := token; self.str := str; self.pos := pos;end;constructor ELex.Create(token: EToken; chr: WideChar; pos: integer);begin self.token := token; self.chr := Char(chr); self.pos := pos;end;function ELex.debug: WideString;const tokenStr : array [EToken] of String = ('N/A', 'End of expression', 'Error', '(', ')', ',', 'Operator', 'Identifier', 'Number', 'Integer', 'String');begin Result := tokenStr[token]; case token of tkOperator : Result := Result + ':' + chr; tkIdentifier, tkNumber, tkInteger, tkString: Result := Result + ':' + str; end; Result := Result + ' at pos:' + IntToStr(pos);end;{ EScan }constructor EScan.Create;begin inherited; OwnsObjects := true; ErrorMessage := '';end;destructor EScan.Destroy;begin inherited;end;function EScan.GetItem(Index: Integer): ELex;begin result := inherited Items[Index] as ELex;end;function EScan.pars(str: WideString): boolean;var idx, start_idx, len : integer; c : WideChar; s : WideString; ctoken: EToken;begin len := Length(str); idx := 1; s := ''; ctoken := tkNA; while (idx
Commenter la réponse de cs_Delphiprog
mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 18 août 2008 à 11:47
0
Utile
Salut DelphiProg,

ouais ben c'est exactement de ça que je suis parti.

J'ai même essayé d'inclure juste ça dans un bête projet console, avec program/begin/end.

Mais j'ai toujours la même erreur...

Soit il faut que je mette mon ExprParsercomplètement à nu, en ne laissant que les déclarations (me reste plus que :

...

implementation

// tout commenté

end.

Je ne sais pas ce qui cause cette erreur.

Et puis ce qui est moche c'est que le compilo me donne la première ligne (et ce même si je vire les commentaires pour ne garder que "unit ExprParser" en 1e ligne, ou même en 2e ligne avec la 1e ligne sautée)

Arf...

c'est dommage.

ça aurait sûrement été la réponse à mon blem.

Quoique, t'es sûr que ça parse une requête SQL, et pas juste toute expression avec des parenthèses d'une manière générique pour les compter ?

J'ai essayé ton lien mais il a l'air mort :D

Merci pour tes prompts posts DelphiProg.
Commenter la réponse de mengele
mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 2 sept. 2008 à 09:44
0
Utile
Merci agilogmail.

Je savais pas qu'une condition (0=1) faisait que la requête ne "s'intéresse plus au reste'. Mais ouais... c'est pas bête

Entre temps j'ai trouvé sur un autre forum cette possibilité (vu qje je suis sous SQL Server) :
Il suffit apparamment d'envelopper la requête par



SET FMTONLY ON
--Requête SQL
SET FMTONLY OFF

ça a exactement l'effet recherché : ça teste juste sa syntaxe sans l'exécuter.

Cela dit ta technique est plus générique vu que c'est du SQL et ça marchera pour tous les SGBD.

Salut
Commenter la réponse de mengele
mengele 30 Messages postés samedi 16 octobre 2004Date d'inscription 12 mai 2010 Dernière intervention - 2 sept. 2008 à 09:51
0
Utile
PS oour AGILOGMAIL : 
       Pour D7 ça ne tient pas qu'à moi mais à la boîte dans laquelle je bosse
       Surtout que je meurs d'envie de pouvoir utiliser des tas de composants qui ne compilent pas sous D4.
       Et puis les marques et points d'arrêts sont très mal gérés... bref j'aimerais aussi que ce que tu proposes voie le jour.  T'inquiète je suis pas sadomaso. Si j'ai l'occasion de "partir" et de "courir" je le ferai sans hésiter.

Voilà pour la p'tite HS au post
Commenter la réponse de mengele
AGILOGMAIL 5 Messages postés mercredi 2 juillet 2008Date d'inscription 15 mars 2010 Dernière intervention - 2 sept. 2008 à 10:00
0
Utile
Bonjour Mengele,

Super ta syntaxe, je vais l'essayer !
Il faudrait que je retrouve son équivalent en Oracle et en MySql !!!

je suis passé en D7 il y a au moins 4 ans, j'ai testé D2005 et D2006, une cata ... Puis je me suis réinterressé à D2007, qui m'a réellement surpris.

La plupart des dev que nous faisons sont toujours en D7, mais nous allons TOUS les migrer en Delphi 2009 Win32 et pour certains autres, les migrer en.NET ASPX avec RadStudio 2009 lorsqu'il sera sorti et j'ai hâte car ce que nous en avons vu lors des Webinars (tard le soir) est impressionnant. Pour les nouveaux dev en WEB on ne sait pas si l'on va pas tout de même passer en C#, on a les compétences, et il y a clairement un marché alors ...
Petit HS au post également.

Bonne journée
Jean-Mi

rien de sert de courir, il faut partir à point.
Certes, mais il faut partir.
Commenter la réponse de AGILOGMAIL

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.