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

 Delphi Discussion :

Delphi 7: requête sql BDE


Sujet :

Delphi

  1. #1
    Nouveau membre du Club
    Delphi 7: requête sql BDE
    Bonjour tout le monde,
    je reviens vers vous concernant un ancien projet développé en D7 avec une base de données paradox donc en BDE,
    j'ai été contraint de revenir dessus!

    C'est un programme pour la gestion des abonnements pour un client.
    Il y a deux tables Abonne(Id_ab, nom_ab, prenom_ab...etc) et Abonnement(Id_abm, dateD_abm, dateF_abm, validite_abm(true/false)...Id_ab) et aussi et bien sur d'autres tables...lol.

    >Explication:

    Chaque abonné ne peut avoir qu'un seul abonnement en cours de validité, mais les anciens abonnements restent dans la base de données et le champ validite_abm reçoit false cela se passe lors de l'exécution de l'application par un code qui vérifie les dates des abonnements par rapport à la date actuelle dans l’événement OnCreate de la forme principale...jusque-là tout est OK

    >Mon problème:

    Besoin de votre aide pour élaborer une requête sql afin d'afficher les abonnés qui n'ont pas d'abonnement en cour de validité.
    Je vous rappelle que l'abonné peut avoir un abonnement en cour de validité et aussi au même temps d'anciens abonnements qui ne sont plus Valides (validite_abm=false);
    autrement dit si je fais un " select .......where abonement.validite_abm=false"
    cela m'affiche certes les abonnements expirés mais ceux qui ont un abonnement en cours de validité se voient affichés dans la liste des abonnés non autorisé d'accès vu ses anciens abonnements !!!

  2. #2
    Rédacteur/Modérateur

    Bonjour,

    mais les anciens abonnements restent dans la base de données et le champ validite_abm reçoit false cela se passe lors de l'exécution de l'application par un code qui vérifie les dates des abonnements par rapport à la date actuelle dans l’événement OnCreate de la forme principale...jusque-là tout est OK
    bof ! Ce n'est pas vraiment ce que je qualifierai très carré mais j'ai retrouvé cette conversation qui déjà en faisait état. Puis qu'il y a les colonnes dateD_abm, dateF_abm obtenir les abonnements en cours par rapport à la date du jour doit pouvoir s'obtenir par le SQL
    Code SQL :Sélectionner tout -Visualiser dans une fenêtre à part
    SELECT id_abm, dateD_abm, dateF_abm, id_ab FROM  Abonnement WHERE :NOW>= dateD_abm AND :NOW<=dateF_abm

    Obtenir les abonnés (une seule fois) n'ayant aucun abonnement en cours devrait pouvoir s'obtenir en utilisant une technique que l'on nomme dans les SGBDs modernes : une CTE. Avec Paradox, il est possible d'utiliser un texte SQL comme une table donc si le précédent SQL est enregistré au même endroit que les tables il doit être possible de faire une jointure entre les abonnements "actifs" et la table des abonnements

    Code SQL :Sélectionner tout -Visualiser dans une fenêtre à part
    SELECT A.id_ab,S.id_ABM AS ABENCOURS FROM Abonnement A LEFT JOIN ABONNEMENTENCOURS.SQL S ON A.id_ab=S.id_ab

    n'obtenir que les abonnements des utilisateurs sans abonnements actifs se fera en ajoutant la clause WHERE ABENCOURS IS NULL
    à partir de la même technique (enregistrement du texte SQL en ABENCOURS.SQL)

    Code SQL :Sélectionner tout -Visualiser dans une fenêtre à part
    SELECT DISTINCT(id_ab) FROM ABENCOURS.SQL WHERE ABENCOURS IS NULL
    vous obtiendrez les utilisateurs qui n'ont aucun abonnement en cours

    Il y a certainement mieux le dernier SQL est certainement évitable
    Code SQL :Sélectionner tout -Visualiser dans une fenêtre à part
    SELECT DISTINCT A.id_ab,S.id_ABM AS ABENCOURS FROM Abonnement A LEFT JOIN ABONNEMENTENCOURS.SQL S ON A.id_ab=S.id_ab WHERE ABENCOURS IS NULL


    P.S. La syntaxe est approximative il manque peut-être des guillemets " " pour l'utilisation des textes SQL, écrit de mémoire et sans jeu d'essai difficile d'en être sûr
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  3. #3
    Membre actif
    Bonsoir,
    Vous faîtes bien compliqué.
    Code sql :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    select * from Abonne a
    where a.Id_ab not in (select b.Id_Ab from Abonnement b where b.validite_abn=true)

    Tous les abonnés dont l'Id n'est pas dans les Abonnements valides.
    (testé seulement avec Db2, à vérifier avec d'autres DB)
    solilog

  4. #4
    Rédacteur/Modérateur

    Citation Envoyé par solilog Voir le message

    Vous faites bien compliqué.
    Oui mais je n'aime pas les WHERE IN ( ) et je doute de la fiabilité du processus de mise à jour de validite_abn
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  5. #5
    Membre actif
    Bonjour,
    Vous n'aimez pas (bizarre) mais c'est la seule façon simple et concise de faire, et c'est rapide. On peut aussi utiliser le "not exists" faire
    Code sql :Sélectionner tout -Visualiser dans une fenêtre à part
    select * from Abonné a where not exists (select b.Id_Ab from Abonnement where a:Id_Ab=b.Ib_ab and b.Validite_abn=true)
    mais je préfère le not in du 1er exemple.

    solilog

  6. #6
    Membre émérite
    Attention le SQL de Paradox n'est pas un SQL Standard. Le type de requête de Paradox est le QBE

  7. #7
    Rédacteur/Modérateur

    re,

    Le SQL Local terme que je préfère à QBE qui pour moi fait plus référence à l'utilitaire de création de requête par l'exemple (Query By Exemple) est très limité

    J'ai eu des doutes concernant WHERE EXISTS mais j'ai pu retrouver ce site http://www.nknabe.dk/localsql/index.html j'adhère donc plus à cette seconde proposition
    Code SQL :Sélectionner tout -Visualiser dans une fenêtre à part
    select * from Abonne a where not exists (select b.Id_Ab from Abonnement where a:Id_Ab=b.Ib_ab and b.Validite_abn=true)

    en remplaçant la colonne Validit_abn par un travail sur les dates (on ne se refait pas)
    Code SQL :Sélectionner tout -Visualiser dans une fenêtre à part
    select * from Abonne a where not exists (select b.Id_Ab from Abonnement where a:Id_Ab=b.Ib_ab and dateD_abm>=:now AND dateD_ab=:NOW)

    Je me demande même si la syntaxe
    Code SQL :Sélectionner tout -Visualiser dans une fenêtre à part
    select * from Abonne a OUTER JOIN (select b.Id_Ab from Abonnement where dateD_abm>=:now AND dateD_ab=:NOW) b ON (a.id_ab=b.Ib_ab)

    serait acceptée mais bon, sans jeu d'essai je ne vais pas m'y prendre le chou
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  8. #8
    Membre émérite
    Non je parlais du QBE qui est une transcription en Delphi du QBE de l'outil Paradox et est bien plus puissant que le SQL pour ce type de
    base. J'ai mis en pièce jointe l'unité QBE.PAS
    Exemple :

    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
     
    var
      QBE1: TQBE;
      Tb1 : TTable ;
      iNbre1,iNbre2 : integer ;
      stTypeTraitement : string ;
      bOk : Boolean ;
      sr1 : TSearchRec;
    begin
      QBE1 := TQBE.Create (nil) ;
      QBE1.RequestLive := False ;
      QBE1.BlankasZero := False ;
      QBE1.AuxTables := False ;
      QBE1.AnswerType := ttParadox ;
      Tb1 := TTable.Create (nil) ;
      Tb1.DatabaseName := 'MABASE' ;
      QBE1.QBE.text :=
          'Query ¦'+
          '¦'+
          'Import.DB | IDLOT                         |¦'+
          '			     | Check calc count all as Nbre2 |¦'+
          '¦'+
          'EndQuery';
      QBE1.AnswerTable := ':MABASE:T1.DB' ;
      QBE1.open ;

  9. #9
    Membre confirmé
    Bonjour,
    Citation Envoyé par SergioMaster Voir le message
    je doute de la fiabilité du processus de mise à jour de validite_abn
    Tout à fait d'accord avec Sergio lorsque je lis ça:
    Citation Envoyé par lotfi.lahcene Voir le message
    Chaque abonné ne peut avoir qu'un seul abonnement en cours de validité, mais les anciens abonnements restent dans la base de données et le champ validite_abm reçoit false cela se passe lors de l'exécution de l'application par un code qui vérifie les dates des abonnements par rapport à la date actuelle dans l’événement OnCreate de la forme principale...jusque-là tout est OK
    On ne peut être sûr que de la validité de l'abonnement de l'abonné sélectionné, ou lofti.lahcene devrait nous donner des détails sur le code.

    André

  10. #10
    Membre émérite
    Finalement c'est simple : tu interroge la table abonnement (select distinct) tu comptes le nombre de validite_abm par abonné et tu "calc" le max de validite_abm
    Les non abonnés ont un nombre à 1 et max à false. Si tu veux je t'envoie l'exemple

  11. ###raw>post.musername###
    Nouveau membre du Club
    Bsr à tous,
    en fin de compte j'ai opter pour la solution la plus rapide et facile vu l'urgence
    SQL :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    select a.nom_ab, a.prenom_ab, a.photo_ab from abonne a where not exists ( select b.num_ab, b.validite_abm from abonnement b where a.num_ab=b.num_ab and b.validite_abm=true)


    mais j'irai volontiers explorer la solution qu'a proposé @SergioMaster

    Obtenir les abonnés (une seule fois) n'ayant aucun abonnement en cours devrait pouvoir s'obtenir en utilisant une technique que l'on nomme dans les SGBDs modernes : une CTE. Avec Paradox, il est possible d'utiliser un texte SQL comme une table donc si le précédent SQL est enregistré au même endroit que les tables il doit être possible de faire une jointure entre les abonnements "actifs" et la table des abonnements
    mais pour ce qui à été dit concernant la fiabilité du processus de mise à jour de validité_abm ma réponse est : "ça fonctionne bien jusque là"

    Code:
    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
    procedure TForm3.FormCreate(Sender: TObject);
    begin
    tableabm.Open;
    while not tableabm.Eof do
     begin
      if (TableabmDated_abm.Value<=date)and(TableabmDatef_abm.Value>=date) then
       begin
        tableabm.Edit;
        TableabmValidite_abm.Value:=true;
        tableabm.Post;
        tableabm.FlushBuffers;
       end
     else
      begin
       tableabm.Edit;
       TableabmValidite_abm.Value:=false;
       tableabm.Post;
       tableabm.FlushBuffers;
      end;
      tableabm.Next;
     end;
    tableabm.Close;
    KeyPreview:=true;\\hors contexte 
    end;

    SergioMaster serte le champ validite_abm peut etre evité car on peut traité les dates directement mais vu que lors de ce projet je n'utilisait pas bcp le SQL...

    Merci à tous
      0  0

###raw>template_hook.ano_emploi###