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 et requetes SQLITE


Sujet :

Delphi

  1. #1
    Membre du Club
    DELPHI et requetes SQLITE
    Bonjour à tous !

    Je suis en train de finaliser, grâce à votre aide, un quizz visuel, basé sur le glisser/déposer d'images sur des emplacements imposés.
    Je désire à présent créer une base de données pour que des utilisateurs inscrits puissent se connecter et être identifiés par un mot de passe.

    J'ai pour l'instant créé une bdd de 3 utilisateurs pour tenter de me "dégrossir sur sqlite.

    Je vous joins un pdf qui relate la problématique et le code que j'ai exploité sur embarcadero et modifié un peu....

    Je souhaite que lorsqu'un utilisateur identifie par son nom et mot de passe, je récupère ces données dans ma bdd pour valider ou non la connexion.

    Quand je fais une identification sur "id", tout est ok, et ca marche sur DB Brower et Delphi10.3 (vcl)

    Mais par "nom" ou "mdp", ca fonctionne bien sur les requêtes de DB Browser, mais pas en dans Delphi.
    C'est d'autant plus improbable dans le cas de "nom", il y a des apostrophes qui encadrent le nom dans la requête DB Browser, ce qui est très
    ardu sous Delphi où les apostrophes sont en plus des éléments d'interprétation du langage...

    1/ Peut-on réaliser une identification d'un utilisateur par le nom ou le mdp sous delphi, ou suis-je condamné à passer l'id?

    2/ Sur les tutos, beaucoup sont orientés vers une lecture de champs communs en liste, par exemple tous les noms ou tous les prénoms, ceux qui équivaut à une lecture par colonne. Pourquoi pas des tutos pour une lecture par ligne, c'est à dire, tous les champ d'un seul utilisateur (son nom, son prénom, son mdp)? Est-ce inutile souvent ou difficile?

    Merci à tous pour vos éclairages potentiels......
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    nit bdd_27_03;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Extctrls, StdCtrls, Data.SqlExpr,
      Data.DbxSqlite, Data.FMTBcd, Data.DB;
     
    type
      TForm8 = class(TForm)
        bpConnect: TButton;
        bpExecute: TButton;
        SQLConnection1: TSQLConnection;
        OutputMemo: TMemo;
        SQLQuery1: TSQLQuery;
        procedure bpConnectClick(Sender: TObject);
        procedure bpExecuteClick(Sender: TObject);
        procedure ShowSelectResults();
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form8: TForm8;
     
    implementation
     
    {$R *.dfm}
     //----------------CONNEXION-----------------------------------------
    procedure TForm8.bpConnectClick(Sender: TObject);
    begin
        SQLConnection1.Params.Add('Database=h:\test_mars_2020.db');
      try
        // Establish the connection.
        SQLConnection1.Connected := true;   // etablit la connexion
        bpExecute.Enabled := true;
        outputMemo.Text := 'Connection établie!';
      except
        on E: EDatabaseError do
          ShowMessage('Exception raised with message' + E.Message);
      end;
    end;
     
     
    //--------------------Analyse requetes---------------------------------------------
    procedure TForm8.bpExecuteClick(Sender: TObject);
    var ma_requete : string;
    begin
          outputMemo.ClearSelection;
     
     
     
      ma_requete := 'SELECT * FROM utilisateurs where nom = DUPONT'  ;
      try
        SQLQuery1.SQL.Text := ma_requete;  // toute la requete est contenue  dans query
        SQLQuery1.Active := true;     // Données débloquées ou pas
      except
        on E: Exception do
          outputMemo.Text := 'Exception raised with message: ' + E.Message;
      end;
     
      ShowSelectResults();  // procedur montrer les résultats
    end;
     
     //-----------------------------------------------------------------------
     procedure TForm8.ShowSelectResults();
    var
       ma_liste: TStringList;
      currentField: TField;
      currentLine: string;
       i : integer;
     
     
     begin
      showmessage (' j''arrive dans showresults');
     
      if not SQLQuery1.IsEmpty then
      // si la le retour n'est pas vide alors faire...
     
     
      begin
         SQLQuery1.First;
         // le pointeur se place sur le premier enregistrement.
     
          ma_liste := TStringList.Create;
         // Créer la liste de chaine nommée "ma-liste"
     
     
        try
          SQLQuery1.GetFieldNames(ma_liste);
          // récupère les champs dans ma_liste
     
     
            //currentLine := '';
     
            for i := 0 to ma_liste.Count - 1 do
            // pour chaque valeur récupérée faire...
     
     
            begin
     
              currentField := SQLQuery1.FieldByName(ma_liste[i]);
               showmessage (' je traite la valeur indexée i' +
               (currentfield).AsString + ' ' + i.ToString );
                // choix du champ  traité "i"
     
              currentLine := currentLine + ' ' + currentField.AsString;
              showmessage(' j''ajoute un nouveau champ dans currentline traitée');
               // ajouter à la chaine la valeur du champ traité
            end;
     
     
            outputMemo.Lines.Add(currentLine);
            showmessage (' je viens de finir ma ligne et je l''afiche');
              // ajoute la valeur de la ligne sur l'affichage
     
     
     
     
     
        finally         // IMPERATIF A LA FIN
          ma_liste.Free;   //supprimer l'objet liste de chaine
        end;
      end;
    end;
     
     
     
     
     
     
     
     
    end.

  2. #2
    Rédacteur/Modérateur

    Bonjour,

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
     ma_requete := 'SELECT * FROM utilisateurs where nom = DUPONT'  ;

    Le cas typique d'une requête non paramétrée alors qu'elle devrait l'être

    Nom est très certainement une colonne de type Texte que, pour un peu plus de facilité, vous auriez pu déclarer de type STRING d'une taille plus réduite.

    1/ Peut-on réaliser une identification d'un utilisateur par le nom ou le mdp sous delphi
    Considérez ce code
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     with TFDQuery.Create(Self) do
     begin
       Connection:=SQLConnection1;
       Open('SELECT * FROM utilisateurs where nom =:n AND pwd=:p',[edtUtilisateur.text,edtMotdepasse.text]);
       if FieldByName('nom').IsNull 
          then  showmessage('Erreur de connexion')
          else showmessage('Bonjour '+fieldbyName('prenom').asString);
     end;

    La requête est une requête paramétrée, les paramètres n et p sont notés avec un ':' devant, nommés, on peut aussi y accédé grâce à l'instruction
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
     FDQuery1.ParamByName('n').asString:='DUPONT';

    dans le code que je vous indique vous pouvez même ne pas les nommer en remplaçant ceux-ci par un ? (cela fonctionne aussi )

    Le code que je vous ai montré est un code dit dynamique, la requête étant créée au runtime.
    2/ Sur les tutos, beaucoup sont orientés vers une lecture de champs communs en liste, par exemple tous les noms ou tous les prénoms, ce qui équivaut à une lecture par colonne. Pourquoi pas des tutos pour une lecture par ligne, c'est-à-dire, tous les champs d'un seul utilisateur (son nom, son prénom, son mdp)? Est-ce inutile souvent ou difficile?
    En général si l'on fait un
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    SELECT nom,prénom,mdp from utilisateurs
    on obtient bien évidemment un certain nombre de lignes qu'effectivement l'on affiche dans une grille ou une liste
    mais si vous faites une requête avec une clause where comme indiquée au-dessus vous ne devriez obtenir qu'un singleton (une seule ligne), ce devrait même être une contrainte de votre table.
    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 du Club
    Merci pour les pistes.
    Merci beaucoup, je vais tenter de décortiquer toutes ces idées!

  4. #4
    Membre du Club
    toujours pas résolu....
    j'en reviens à mon bout de code :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    procedure TForm8.bpExecuteClick(Sender: TObject);
    var ma_requete : string;
     
    begin
          outputMemo.ClearSelection;
           n := 'dupont';
            q :=2;
     
      ma_requete := 'SELECT * FROM utilisateurs where id = :q' ;
      try
        SQLQuery1.SQL.Text := ma_requete;
        showmessage (' ma_requete : ' +  SQLQuery1.SQL.Text );


    Si je lance la requête affichée est :

    Autrement dit, Le traitement SQL ne comprend pas que :Q est un paramètre nommé, mais le traite comme un élément de la chaine et donc, ce ne marche pas. Pour être ok, avec un paramètre integer, ca marche si je fais ceci :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
         n := 'dupont';
            q :=2;
     
      ma_requete := 'SELECT * FROM utilisateurs where id = ' + q.ToString ;
      try
        SQLQuery1.SQL.Text := ma_requete;
        showmessage (' ma_requete : ' +  SQLQuery1.SQL.Text );


    La requête devient : et ca marche, ouf!!

    Le problème est que mon paramétrage par le Nom est encore plus déroutant car il n'est pas interprété ainsi même avec les ":" devant la variable....

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
       n := 'dupont';
            q :=2;
     
      ma_requete := 'SELECT * FROM utilisateurs where id = :n' ;
      try
        SQLQuery1.SQL.Text := ma_requete;
        showmessage (' ma_requete : ' +  SQLQuery1.SQL.Text );


    la requête est toujours :
    le tout est traité comme une chaine standard sans se rendre compte que je désire un paramètre nommé... Pour lui, le ":n" est un vulgaire morceau de chaine de caractère sans rien de particulier.

    Et si je le place hors de la chaine, comme le Q.ToString qui paramètre le Q integer, il me manquera toujours des apostrophes, avant et après le nom, et le nom se trouve traité comme un nom de champ de données de la base, et il me dit qu'il n'y a pas de colonne nommée ainsi....

    Je tourne en rond méchamment.. Il y a vraiment un truc (voir même plusieurs...) qui m'échappe(nt??)

  5. #5
    Modérateur

    Oui : c'est le Query qui sert à affecter une valeur aux paramètres nommés dans leur SQL, sur le modèle (je ne connais pas la syntaxe exacte) :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
      ma_requete := 'SELECT * FROM utilisateurs where id = :q' ;
      try
        SQLQuery1.SQL.Text := ma_requete;
        SQLQuery1.ParamByName('q').AsInteger := 2; // affecte la valeur au paramètre
    Delphi 5 Pro - Delphi 10.3.2 Rio Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  6. #6
    Rédacteur/Modérateur

    Bonjour,

    Tourlourou à raison.
    Il ne sert à rien de vouloir voir l'interprétation du SQL après passage du paramètre, cela ne fonctionnera pas.
    Ce code :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
      showmessage (' ma_requete : ' +  SQLQuery1.SQL.Text );

    revient à écrire.
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
      showmessage (' ma_requete : ' + ma_requete);


    AMHA. Vous partez du mauvais pied. Tout d'abord puisque Delphi10.3 il y a pourquoi n'utilisez-vous pas les composants Firedac plutôt que DBExpress ? (Je vous ai montré une manière de faire dans mon post précédent). Parce que vous utilisez l'explorateur de données pour avoir les composants ou par choix ? N'oubliez pas que DBexpress nécessite des DLL supplémentaires lors du déploiement (et, acessoirement, que SQlite est un SGBD mono utilisateur).


    Si vous voulez tout tracer comme vous le faite vous n'êtes pas sorti de l'auberge ! Au moins, avec Firedac pourriez-vous au moins faire du monitoring

    Ensuite vous devez bien comprendre SQL et ce que cela nécessite. Une valeur chaine doit toujours se trouver entre guillemets.

    Votre 3° requête
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
       n := 'dupont'; 
      ma_requete := 'SELECT * FROM utilisateurs where id = :n' ;

    ne peut fonctionner car :
    1. vous vous trompez de colonne (cela devrait être nom)
    2. n est une chaine, vous devez donc renseigner une chaine dans le SQL c.a.d. ma_requete := 'SELECT * FROM utilisateurs where nom='+Quotedstr(n) ;

    Nota : Utiliser une requête non paramétrée peut ouvrir la porte à l'injection de SQL.

    Pour vous aider, en zip, ce que vous semblez vouloir réaliser, avec l'utilisation du monitoring de firedac (outil)
    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

  7. #7
    Membre du Club
    le ciel s'éclaircit...
    En effet, il y avait encore trop de flou pour le passage de paramètres dans mes requêtes. Je ne voyais pas trop comment un :n perdu dans une chaine pouvait être considéré ensuite comme un paramètre.
    Avec vos précisions, à tourlourou, et bien sur à SergioMaster, tout s'éclaircit. Sans faire encore de la haute voltige en SQL, je comprends mieux les mécanismes et à présent, j'arrive à faire des requêtes paramétrées qui fonctionnent.
    Un grand merci à vous donc! SergioMaster a même pris la peine de créer un petit projet pour moi, qui mouline des requêtes paramétrées de formes diverses pour observer tranquillement leurs comportements, une mine d'or pour moi qui débute!! Chapeau et merci pour le temps passé!
    Résolu donc. A bientôt surement pour d'autres problématiques!....

###raw>template_hook.ano_emploi###