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

C++Builder Discussion :

Récupérer plusieurs records d'un DataSet


Sujet :

C++Builder

  1. #1
    Membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2009
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 65
    Points : 41
    Points
    41
    Par défaut Récupérer plusieurs records d'un DataSet
    Bonjour,

    J'ai un petit problème que je n'arrive pas à résoudre (pour le moment) et je sollicite votre aide.
    Dans mon application, dans le but d'améliorer les performances, je charge une table entière d'une base de données dans un TADODataSet pour pouvoir interroger ce DataSet et non plus passer par la BDD (beaucoup plus lent car ça passe par le réseau). Je fais ceci en exécutant la requête via ce DataSet, c'est-à-dire en initialisant sa propriété CommandText avec la requête voulue (SELECT) et en passant la propriété Active à true. Jusque-là, pas de souci.

    Le problème est que je ne peux pas me contenter d'utiliser ce seul DataSet dans mon application, j'ai en fait besoin de le consulter pour y trouver des records en fonction d'un certain critère (un des champs doit être égal à une certaine valeur). J'ai déjà fait ceci précédemment grâce à la méthode Locate de TADODataSet (et ça marche très bien) parce que je ne devais localiser qu'UN SEUL record, ce qui n'est plus le cas maintenant car je peux avoir plusieurs records pour une même valeur de champ.


    Le problème est que Locate ne localise que le premier enregistrement correspondant au critère. J'aurais en fait besoin de localiser les records voulus dans le TADODataSet, et les récupérer afin de créer un second TADODataSet ne contenant QUE ces records.
    Est-ce possible ? Si oui, comment faire cela ?
    Merci d'avance.

  2. #2
    Membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2009
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 65
    Points : 41
    Points
    41
    Par défaut
    En gros, pour simplifier, ce que je cherche à faire c'est de faire comme si j'exécutais une requête SQL avec critère de sélection (WHERE) sur une table en BDD, sauf que je veux le faire sur un TADODataSet. Et je veux me retrouver avec un autre TADODataSet ne contenant que les records correspondant à la sélection.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2012
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 58
    Points : 31
    Points
    31
    Par défaut
    Je ne connais pas trop l'objet TADODataSet donc je te laisse gérer cette partie, mais concernant l'enregistrement de plusieurs record ça ne semble pas très compliqué.

    Dans ton cas, il me semble que l'utilisation d'un TSQLQuery est plus appropriée étant donné qu'il est fait exprès pour récupérer des données, il te faut donc faire ceci :

    Code C++ : 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
    SQLQuery1->ExecSQL=false; //pour éviter les erreurs
    SQLQuery1->SQL->Clear(); //pour éviter les erreurs
    SQLQuery1->SQL("SELECT * FROM ta_table");
    SQLQuery1->ExecSQL=true;
     
    //On commence à partir de ton premier ID
    if( SQLQuery1->RecordCount != 0) {
    for(int i=SQLQuery1->FieldValues["id"]; i<SQLQuery1->RecordCount; i++) {
     
    SQLQuery1->ExecSQL=false; //pour éviter les erreurs
    SQLQuery1->SQL->Clear(); //pour éviter les erreurs
    SQLQuery1->SQL("SELECT * FROM ta_table WHERE ta_condition and id= ' "+IntToStr(i)+" ' ");
    SQLQuery1->ExecSQL=true;
     
    //On regarde les lignes une par une si elles correspondent à ta condition
    if(SQLQuery1->RecordCount != 0) {
    //Si c'est le cas
    //Tu récupères tes données avec SQLQuery1->FieldValues["ton_champ"];
    //Et tu envoies où tu veux
    }
    }
    }

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    @chapitre37, le code fourni en exemple est très approximatif et très mal indenté (il aurait été bien de le préciser)
    ExecSQL est une fonction avec un paramètre booléen, et non une propriété donc pas d'affectation, une confusion avec le paramètre Active
    ExecSQL est réservé au DML (INSERT, UPDATE ou DELETE) et Active au DQL (SELECT)
    la Propriété SQL est un TStrings, l'ajout se fait par Add() d'ailleurs, au lieu de faire Clear\Add, il suffit de modifier la propriété Text
    RecordCount avec un TSQLQuery il faut l'utiliser avec précaution !
    Manque le Next(), la boucle fournie ne lit que le premier enregistrement n fois !

    A Lire : Utilisation de TADODataSet
    Le Composant TADOQuery est un peu plus pratique qu'un TADODataSet

    @Tenebrous, je n'ai pas compris ton problème, tu es libre de créer autant d'instance que TADODataSet que tu le souhaites, tu peux lancer plusieurs SQL sur la même ou différentes tables avec le même ou plusieurs instances en fonction de tes besoins

    Utilise un TADOConnection pour éviter la répétition de la ConnectionString !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    TADODataSet* DS1 = new TADODataSet(NULL);
    DS1->Connection = ADOConn; // objet global dans un TDataModule par exemple ou gérer par un Singleton
    DS1->CommandText = "SELECT * FROM maTable WHERE Champ = :param1";
    DS1->Parameters->ParamByName("param1")->AsString = "Valeur";
    DS1->Open();
    while ( ! DS1->Eof)
    {
      ShowMessage(DS1->FieldByName('...')->AsString);  
     
      DS1->Next();
    }
     
    delete DS1; // a toi de voir la durée de vie de tes objets
    Avec Prepared, tu pourrais optimiser la requête si l'utilises fréquemment en changeant juste la valeur du critère de recherche
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2012
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 58
    Points : 31
    Points
    31
    Par défaut
    Concernant les "Active" et "ExecSQL", en effet j'ai inversé, au temps pour moi, je savais bien que l'un était pour les SELECT et l'autre pour le reste des fonctions, mais j'ai pas pris les bons. x)

    Ensuite, si j'effectue un Clear/Add, c'est que ayant déjà eu affaire au SQLQuery, j'ai eu l'habitude d'utiliser cette combinaison, pour éviter les "fusions" de requêtes, contrairement à l'objet SQLDataSet, qui a directement une propriété "CommandText".

    Enfin, je ne suis pas d'accord avec toi, la boucle ne lit pas la première ligne "n" fois. Justement, dans ma boucle, j'effectue de nouveau un SELECT en ne prenant la ligne dont l'ID est égal à la valeur de i, de ce fait, à chaque passage dans la boucle, cela sélectionne la ligne suivante. Certes il y a sans doute de meilleurs moyens, mais bon, j'ai encore beaucoup à apprendre niveau optimisation de code.

    Pour ce qui est de l'indentation mal faite, j'avais écrit le code directement ici, donc pas moyen de faire de "TAB" pour décaler, c'est modifié.

    Code C++ : 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
    SQLQuery1->ExecSQL=false; //pour éviter les erreurs
    SQLQuery1->SQL->Clear(); //pour éviter les erreurs
    SQLQuery1->SQL("SELECT * FROM ta_table");
    SQLQuery1->ExecSQL=true;
     
    //On commence à partir de ton premier ID
    if( SQLQuery1->RecordCount != 0)
    {
    	for(int i=SQLQuery1->FieldValues["id"]; i<SQLQuery1->RecordCount; i++)
    	{
     
    		SQLQuery1->ExecSQL=false; //pour éviter les erreurs
    		SQLQuery1->SQL->Clear(); //pour éviter les erreurs
    		SQLQuery1->SQL("SELECT * FROM ta_table WHERE ta_condition and id= ' "+IntToStr(i)+" ' ");
    		SQLQuery1->ExecSQL=true;
     
    		//On regarde les lignes une par une si elles correspondent à ta condition
    		if(SQLQuery1->RecordCount != 0)
    		{
    			//Si c'est le cas
    			//Tu récupères tes données avec SQLQuery1->FieldValues["ton_champ"];
    			//Et tu envoies où tu veux
    		}
    	}
    }

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Ah, oui, pour le i, cela suppose des ID continus, c'est tout de même très limité comme solution

    Tu as oublié un truc, c'est SQLQuery1, tu l'utilises à l'intérieur de la boucle, donc RecordCount change, ... en fait ta boucle ne fait QUE le premier ID si celui-ci est Unique !
    RecordCount passe de n à 1 dès la première éxécution dans la boucle !

    c'est un peu comme si tu avais fait ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int k = 10;
    for (i := 1; i < k; i++)
      k = i;
    Tu n'as pas compris la problématique de Tenebrous qui souhaite avoir un Query1 ouvert sur toute la table et un autre Query2 uniquement sur un extrait !

    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
    ADOQuery1->Close();
    ADOQuery1->SQL->Text = "SELECT * FROM ta_table"; // tu ne sembles pas connaître toutes les propriétés de la TStrings !
    ADOQuery1->Open();
     
    while ( ! ADOQuery1->Eof)
    {
      TADODataSet* DS1 = new TADODataSet(NULL);
      DS1->Connection = ADOQuery1->Connection;
      DS1->CommandText = "SELECT * FROM maTable WHERE Champ = :param1";
      DS1->Parameters->ParamByName("param1")->AsString = ADOQuery1->FieldByName('...')->AsString;
      DS1->Open();
      if ( ! DS1->IsEmpty())
      {
        ShowMessage(DS1->FieldByName('...')->AsString);  
      }
      delete DS1;
     
      ADOQuery1->Next;
    }
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2012
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 58
    Points : 31
    Points
    31
    Par défaut
    Hum effectivement je n'avais pas pensé à ces deux points là ... au temps pour moi !

    Du coup ta solution semble mieux adaptée.

Discussions similaires

  1. Récupérer valeurs plusieurs tables d'un dataset
    Par McAdam dans le forum VB.NET
    Réponses: 0
    Dernier message: 21/08/2010, 14h39
  2. Réponses: 16
    Dernier message: 19/07/2006, 00h16
  3. Récupérer un record depuis une gridview
    Par Dnx dans le forum ASP.NET
    Réponses: 2
    Dernier message: 07/07/2006, 11h42
  4. [SQL] Récupérer plusieurs lignes spécifiques d'une table
    Par Anduriel dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 29/04/2006, 19h49
  5. [MySQL] récupérer plusieurs tuples depuis un array
    Par psychoBob dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 29/12/2005, 18h17

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