IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Bases de données Delphi Discussion :

Conception / Requête SQL


Sujet :

Bases de données Delphi

  1. #1
    Membre averti Avatar de archonte
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    341
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 341
    Points : 392
    Points
    392
    Par défaut Conception / Requête SQL
    Bonjour à tous !

    La situation
    ADO / Access
    J'ai 2 tables :
    - T_CLIENTS (CLI_ID, CLI_Nom, CLI_Prenom, ...)
    - T_ACHATS (ACH_ID, ACH_Date, ACH_Id_Client, ACH_Montant, ACH_Commentaire, ...)

    Le problème
    Je souhaite récupérer la liste de tous les clients et de leur dernier commentaire en date. J'y arrive par le biais de deux requêtes successives : 1) récupération des noms et prénoms sur la table T_CLIENTS puis, 2) à l'affichage dans un StringGrid, pour chaque client la deuxième requête récupère ACH_Commentaire pour lequel ACH_Date est le plus grand soit :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    strSQL1 := 'SELECT CLI_ID, CLI_Nom, CLI_Prenom FROM T_CLIENTS ORDER BY CLI_Nom, CLI_Prenom';
     
    strSQL2 := 'SELECT ACH_Commentaire FROM T_ACHATS WHERE ACH_Id_Client = :PIdClient1 AND ACH_Date >= ALL ' +
               '(SELECT ACH_Date FROM T_ACHATS WHERE ACH_Id_Client = :PIdClient2)';
    ce qui donne :
    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
    23
    24
    25
    26
    with ADOQry1 do
      begin
        Close;
        SQL.Text := strSQL1;
        Active := true;
     
        if RecordCount > 0 then
        begin
          Fields.DataSet.FindFirst;
     
          while not Fields.DataSet.Eof do
          begin
            with ADOQry2 do
            begin
               Close;
               SQL.Text := strSQL2;
               ParamCheck := true;
               Parameters.ParamByName('PIdClient1').Value := ADOQry1.FieldByName('CLI_ID').AsString;  // résultat de la requête #1
               Parameters.ParamByName('PIdClient2').Value := ADOQry1.FieldByName('CLI_ID').AsString;
               Active := true;
     
               if RecordCount > 0 then
               begin
                 Fields.DataSet.FindFirst;
     
                 etc ....
    Les questions
    Ce code fonctionne, mais je le trouve lourd !

    >> Cette structure de requête vous semble-t-elle adaptée ?
    >> Existe-t-il un moyen de combiner les 2 requêtes avec une jointure ? Est-ce judicieux ?

    NB : pour info : le nombre de clients retourné est faible (<100) et le nombre de lignes d'achat par client à prendre en compte par le moteur SQL aussi (50 en moyenne).

    Merci d'avance pour vos commentaires.
    "Je n'ai jamais rencontré d'homme si ignorant qu'il n'eut quelque chose à m'apprendre."
    Galilée

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 042
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 042
    Points : 40 952
    Points
    40 952
    Billets dans le blog
    62
    Par défaut
    Bonjour , oui la requête est 'lourde'

    Avec Access je vais pas trop m'avancer ( je ne suis pas un fan ) mais je suis sur qu'il est possible d'améliorer la requête 2

    Sous Firebird j'aurais fait
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT FIRST 1 ACH_Commentaire FROM T_ACHATS WHERE ACH_Id_Client = :PIdClient1 ORDER BY ACH_Date DESC
    pour obtenir uniquement le 'dernier enregistrement' en date
    l'astuce étant dans le ORDER BY surtout , le FIRST 1 étant pour limiter le nombre d'enregistrements au 1° (pour optimiser la vitesse : un index sur la date)

    Déjà ceci devrait alléger le code

    Maintenant , comme c'est le matin , la caféine n'est pas encore arrivé au cerveau , mais je suis sur qu'une seule requête peut faire l'affaire
    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

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut
    Bonjour,

    Je ne sais pas si Access supporte les jointures.

    Mais avec Firebird, j'aurai créer la requête ainsi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire, MAX(ACH_Date)
    FROM T_CLIENTS C
       LEFT JOIN T_ACHATS A ON C.CLI_ID = A.ACH_Id_Client
    GROUP BY C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire
    ORDER BY CLI_Nom, CLI_Prenom
    A parfaire, car je n'ai pas tester. J'ai une crainte que Ach_Commentaire conduise à présenter plusieurs lignes. Si c'est le cas, il conviendra de modifier la requête.

    Il y a une meilleur solution avec CTE : Common Table Expression, mais là, je ne pense pas que Access accepte.

    Ne pas oublier non plus les solutions avec deux vues.

    Maintenant, il faut adapter cela à Access.

    Bon courage

  4. #4
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 235
    Points : 8 504
    Points
    8 504
    Par défaut
    Citation Envoyé par seabs Voir le message
    Bonjour,

    Je ne sais pas si Access supporte les jointures.

    Mais avec Firebird, j'aurai créer la requête ainsi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire, MAX(ACH_Date)
    FROM T_CLIENTS C
       LEFT JOIN T_ACHATS A ON C.CLI_ID = A.ACH_Id_Client
    GROUP BY C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire
    ORDER BY CLI_Nom, CLI_Prenom
    A parfaire, car je n'ai pas tester.

    Il y a une meilleur solution avec CTE : Common Table Expression, mais là, je ne pense pas que Access accepte.

    Ne pas oublier non plus les solutions avec deux vues.

    Maintenant, il faut adapter cela à Access.

    Bon courage
    Ta requête ne peut fonctionner, pour chaque commentaire différent du client, tu retournes une ligne avec la date max du dernier commentaire.

    Sinon oui, Access supporte les jointures
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut
    Bonjour,

    Je ne sais pas si Access supporte les jointures.

    Mais avec Firebird, j'aurai créer la requête ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire, MAX(ACH_Date)
    FROM T_CLIENTS C
       LEFT JOIN T_ACHATS A ON C.CLI_ID = A.ACH_Id_Client
    GROUP BY C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire
    ORDER BY CLI_Nom, CLI_Prenom
    A parfaire, car je n'ai pas tester. J'ai une crainte que Ach_Commentaire conduise à présenter plusieurs lignes. Si c'est le cas, il conviendra de modifier la requête.
    Effectivement, après relecture, j'avais ajouter un complément pour indiquer le point négatif de ma requête.

    Je viens d'établir une nouvelle présentation que j'ai pris le temps de tester.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire, ACH_DATE
    FROM T_CLIENTS C
      LEFT JOIN T_ACHATS A ON C.CLI_ID = A.ACH_Id_Client
    WHERE ACH_Commentaire IS NULL OR ACH_DATE = (SELECT MAX(ACH_DATE) FROM T_ACHATS WHERE ACH_Id_Client = C.CLI_ID)
    ORDER BY CLI_Nom, CLI_Prenom
    J'ai mis ACH_Commentaire IS NULL pour présenter les clients n'ayant aucun commentaire. A supprimer si vous ne voulez pas présenter les clients ne possédant aucun commentaire.

    Cette requête est parfaitement adaptable à Access, le modèle étant établi avec Firebird

    Bon courage

  6. #6
    Membre averti Avatar de archonte
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    341
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 341
    Points : 392
    Points
    392
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Bonjour , oui la requête est 'lourde'

    Sous Firebird j'aurais fait
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT FIRST 1 ACH_Commentaire FROM T_ACHATS WHERE ACH_Id_Client = :PIdClient1 ORDER BY ACH_Date DESC
    pour obtenir uniquement le 'dernier enregistrement' en date
    l'astuce étant dans le ORDER BY surtout , le FIRST 1 étant pour limiter le nombre d'enregistrements au 1° (pour optimiser la vitesse : un index sur la date)

    Déjà ceci devrait alléger le code
    ça a toujours l'air simple ... mais je n'y ai pas pensé sur l'instant !! FIRST 1 à remplacer par TOP 1 pour Access.

    Par contre j'ai retenu la requête de seabs

    Citation Envoyé par seabs Voir le message
    Je viens d'établir une nouvelle présentation que j'ai pris le temps de tester
    ça c'est sympa de tester avant ! comme ça je peux !
    Citation Envoyé par seabs Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire, ACH_DATE
    FROM T_CLIENTS C
      LEFT JOIN T_ACHATS A ON C.CLI_ID = A.ACH_Id_Client
    WHERE ACH_Commentaire IS NULL OR ACH_DATE = (SELECT MAX(ACH_DATE) FROM T_ACHATS WHERE ACH_Id_Client = C.CLI_ID)
    ORDER BY CLI_Nom, CLI_Prenom
    J'ai mis ACH_Commentaire IS NULL pour présenter les clients n'ayant aucun commentaire. A supprimer si vous ne voulez pas présenter les clients ne possédant aucun commentaire.

    Cette requête est parfaitement adaptable à Access, le modèle étant établi avec Firebird

    Bon courage
    Requête transposée tel quel. J'ai gardé pour l'instant le test IS NULL. A voir à l'usage. Grand

    Des heures devant mon écran et je n'étais pas arrivé à l'écrire ! Merci encore pour votre rapidité !



    Evidemment :
    "Je n'ai jamais rencontré d'homme si ignorant qu'il n'eut quelque chose à m'apprendre."
    Galilée

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut
    Bonjour,

    Après un nuit de sommeil, les idées sont plus claires.

    Il peut y avoir un souci pour le dernier commentaire, si tu enregistres plusieurs achats dans la même journée.

    La première solution est d'enregistrer la date d'achats avec l'heure exacte.

    La seconde, si tu as des index auto-incrémentés, la dernière écriture sera celle ayant le n° d'index le plus élevé. Dans ce cas, tu modifies la requête ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT C.CLI_ID, CLI_Nom, CLI_Prenom, ACH_Commentaire, ACH_DATE
    FROM T_CLIENTS C
      LEFT JOIN T_ACHATS A ON C.CLI_ID = A.ACH_Id_Client
    WHERE ACH_Commentaire IS NULL OR ACH_ID = (SELECT MAX(ACH_ID) FROM T_ACHATS WHERE ACH_Id_Client = C.CLI_ID)
    ORDER BY CLI_Nom, CLI_Prenom
    Bon courage dans ton développement

  8. #8
    Membre averti Avatar de archonte
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    341
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 341
    Points : 392
    Points
    392
    Par défaut
    Citation Envoyé par seabs Voir le message
    ...
    La seconde, si tu as des index auto-incrémentés, la dernière écriture sera celle ayant le n° d'index le plus élevé.
    ...
    Bon courage dans ton développement
    Effectivement, j'ai fini par avoir cette idée plus simple que de travailler sur des dates après avoir posté ma réponse hier soir ! MERCI de t'être re-pencher sur mon cas A force de le code s'améliore progressivement !
    "Je n'ai jamais rencontré d'homme si ignorant qu'il n'eut quelque chose à m'apprendre."
    Galilée

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 18
    Dernier message: 24/07/2012, 15h08
  2. Conception d'une requête SQL
    Par robin.pariset dans le forum Langage SQL
    Réponses: 5
    Dernier message: 17/10/2007, 10h10
  3. [POO] Problème de conception POO et requêtes sql
    Par redsaint0 dans le forum Langage
    Réponses: 4
    Dernier message: 13/02/2007, 19h59
  4. [Débutant] Conception requêtes SQL
    Par LhIaScZkTer dans le forum Langage SQL
    Réponses: 15
    Dernier message: 10/01/2006, 21h46
  5. Utilisation de MAX dans une requête SQL
    Par Evil onE dans le forum Langage SQL
    Réponses: 7
    Dernier message: 15/06/2004, 18h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo