Decomposition sql - algorithme simple et efficace

Soyez le premier à donner votre avis sur cette source.

Vue 8 350 fois - Téléchargée 581 fois

Description

Une DLL qui permet de décomposer un texte SQL ou de jouer avec et d'avoir la décomposition de chaque Clause.

Pour mon utilisation perso je n'ai pas vraiment besoin de scruter le contenu de la clause From, raison pour laquelle la méthode utilisée pour le traitement de la clause From a des manquements et des limites. J'en ai plus besoin pour mon contrôle qui permet de visualiser des recordsets par passage des paramètres de CommandText et ConnectionString et Criteria.
De ce fait au lieu de Charger la Commande et après faire un .Filter=..., qui n'est pas optimisé je charge directement la commande ajustée sur les bons enregistrements.
Le problème également est que je dois compter les enregistrements, .MoveLast aprés .MoveFirst, il vaut mieux dans tous les cas avoir moins d'enregistrements à parcourir.

En réalité

J'ai ajouté à la propriété get SQL la possibilité de rajouter des valeurs dans les clauses WHERE, HAVING et ORDER BY de la SQL initiale.La propriété Let SQL permet de passer des paramètres jouant également sur les clauses citées plus haut.
On peut reinitialiser les critères et le tri.

L'algorithme utilisé est assez simple, le texte est préformaté en un passage de la chaine SQL et après la lecture devient aisé. Le principe de cette algorithme peut être réutilisé dans bien des cas.

Comme dab, vos commentaires seraient les bienvenus afin que je puisse optimiser le code.

Source / Exemple :


'méthode Init de la Classe
Public Function Init(ByVal psSQL As String, _
    Optional ByVal psLeftNameSeparator As String, _
    Optional ByVal psRightNameSeparator As String, _
    Optional ByVal psTextIdentificator As String)

    If psLeftNameSeparator <> vbNullString Then msLeftNameSeparator = psLeftNameSeparator
    If psRightNameSeparator <> vbNullString Then msRightNameSeparator = psRightNameSeparator
    If psTextIdentificator <> vbNullString Then msTextIdentificator = psTextIdentificator
    
    msSQL = TransformSQL(psSQL)
    
    'Pour mes besoins actuels, je ne joue qu'avec les instructions de la forme
    ' SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ...
    ' au mieux avec TRANSFORM ... SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... PIVOT ...

    
    Call ExtraitVariable("PIVOT", msPivot)
    Call ExtraitVariable("ORDER BY", msOrderBy)
    Call ExtraitVariable("HAVING", msHaving)
    Call ExtraitVariable("GROUP BY", msGroupBy)
    Call ExtraitVariable("WHERE", msWhere)
    Call ExtraitVariable("FROM", msFrom)
    Call ExtraitVariable("SELECT", msSelect)
    Call ExtraitVariable("TRANSFORM", msTransform)
    
End Function

'Propriétés de la classe
Public Property Get SQL(Optional ByVal psWhereCriteria As String, _
    Optional ByVal psHavingCriteria As String, _
    Optional ByVal psSort As String) As String

Public Property Let SQL(Optional ByVal psWhereCriteria As String, _
    Optional ByVal psHavingCriteria As String, _
    Optional ByVal psSort As String, ByVal psSQL As String)

Public Property Get SQLTransform(Optional ByRef psField As String, Optional ByRef psCaption As String) As String

Public Property Get SQLSelect(Optional ByRef psPredicate As String, Optional ByRef paFields As Variant, Optional ByRef paCaptions As Variant) As String

'Propriété Get SQLFrom
'paTables est un tableau des tables utilisées dans la SQL
'paRelationShips est un tableau des relations
'L'algorithme utilisée pour pour cette proprité a des limites certes mais permet de retrouver nos petits dans bien des cas
Public Property Get SQLFrom(Optional ByRef paTables As Variant, Optional ByRef paRelationShips As Variant) As String

Public Property Get SQLWhere() As String

Public Property Let SQLWhere(ByVal psSQLWhere As String)

Public Property Get SQLGroupBy(Optional ByRef paFields As Variant) As String

Public Property Get SQLHaving() As String

Public Property Let SQLHaving(ByVal psSQLHaving As String)

Public Property Get SQLOrderBy(Optional ByRef paFields As Variant) As String

Public Function ClearOrderBy()

Public Property Get SQLPivot(Optional ByRef psField As String, Optional ByRef paColumnsNames As Variant) As String

Conclusion :


Pour aider cette DLL à retrouver les noms de tables dans la clause From, il vaudrait mieux que les tables dans la clause From soient des crochets ([...])

J'espère avoir des avis qui me permettront de voir les manquements et surtout de l'optimiser.

ASIMENGO

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
281
Date d'inscription
jeudi 24 mars 2005
Statut
Membre
Dernière intervention
18 mars 2009

@Yan35: Je précise bien dans le code que je m'intéresse uniquement aux syntaxes de la forme Transform ... select ... from ... where .... group by ... having ..., order by ... pivot ....
Le but n'est même pas de vérifier l'exactitude de la SQL, mais une décomposition dans le but de changer les paramètres des clauses.
Dans mon cas, j'ai un composant datagrid perso, qui permet d'afficher un recordset à partir de CommandText et de ConnectionString que j'utilise beaucoup pour afficher les tables filles, multi-requetage de liste, ...
Au lieu de charger toute la table et actualiser avec la méthode Filter qui rendrait le programme très lourd, j'ai besoin de passer à mon composant un critère externe. Mais les applications sont encore plus complexe, vu que je permet à chaque utilisateur d'avoir sa propre mise en forme de liste, disposition des colonnes et taille, c'est tout simple, je garde dans une table les valeurs de ColumnWithts, et la clause Select.

D'autre part la méthode Init permet de spécifier les délimiteurs de champs, par défaut c'est "[" et "]".

En déhors de l'aspect pratique de la source, l'algorithme utilisé est surtout le point important à assimiler.

A+
Messages postés
185
Date d'inscription
dimanche 29 juin 2003
Statut
Membre
Dernière intervention
20 juin 2013

Bonjour Asimengo et merci pour ce code.
Je viens de le tester car j'y trouve de l'intérêt notamment pour écrire plusieures requêtes qui se ressemblent et éviter de toutes les réécrire en assemblant les clauses similaires, par exemple la clause From qui peut être la même dans plusieurs recordsets qui eux se distingueraient par Select et Where, par exemple.
J'ai 2 remarques à faire : ton code ne fonctionne plus s'il y a des sous-requêtes inclues dans les différentes clauses ; tes séparateurs [ ] sont valables pour Access ou autres mais pas pour MySQL et sans doute d'autres SGBD.
Sinon je trouve dommage sur 284 téléchargements à cette date, personne ne t'a attribué de note.
Je mets 7/10 pour les remarques communiquées.
Cordialement
Messages postés
281
Date d'inscription
jeudi 24 mars 2005
Statut
Membre
Dernière intervention
18 mars 2009

Merci EBARTSOFT, venant de toi c'est un grand compliment.
Messages postés
4525
Date d'inscription
dimanche 29 septembre 2002
Statut
Modérateur
Dernière intervention
22 avril 2019
8
Je remercie asimengo pour perpetuer la tradition du VB6.
Et en plus c'est plutôt bien fait.

@+
Messages postés
281
Date d'inscription
jeudi 24 mars 2005
Statut
Membre
Dernière intervention
18 mars 2009

@Vladam: Je n'ai pas bien compris, en effet je ne cherches qu'à savoir plus si tu pouvais être plus explicite. Je profite également pour ajouter un autre intérêt de la decomposition SQL c'est de pouvoir ajouter/modifier des légendes ou les traduires dans une langue. Il suffira de rajouter des mots clés et après avoir identifier les captions, lire dans une table dictionnaire pour traduire en fonction de la langue choisie au démarrage de l'applis.

Je profite pour corriger un manquement dans la fonction TransformSQL
Remplacer "bParenthesisOpen As Boolean" par "lParenthesisOpen As Long"
et dans le corps de la procédure on aura plutôt
Select Case sCar
Case "(": lParenthesisOpen = lParenthesisOpen + 1
Case ")": lParenthesisOpen = lParenthesisOpen - 1
Case ",":
If (Not bNameBegin) And (lParenthesisOpen = 0) Then
...

NB :
Le but de cette source n'est pas de vérifier la validité d'une SQL mais de la decomposer en supposant qu'à l'origine elle est valide. Sa grande utilité est de permettre l'optimisation des resultats de recordset.
Pour mon utilisation j'ai 2 méthodes la méthodes Refresh qui va faire un .Filter et un .Sort sur les variables sFiltre et sSort et la méthode Requery qui va reécrer la SQL en incluant sFiltre et sSort dans la SQL.

C'est dommage de ne pas avoir des retours d'utilisation qui bien évidemment permettent de faire évoluer le code et surtout d'avoir les mises à jour sinon certaines mises à jour ne se voient pas reloader.
Afficher les 8 commentaires

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.