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

Delphi Discussion :

Comment ajouter des colonnes à une DBGRID ?


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    Septembre 2004
    Messages
    516
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Septembre 2004
    Messages : 516
    Par défaut Comment ajouter des colonnes à une DBGRID ?
    Delphi 10.3.3 / Fire DAC / MySQL /

    Bonjour,

    J'ai une DBGRID qui m'affiche le contenu d'une table. Très bien, ça marche.
    Une des colonnes de cette table affiche un champ qui contient du texte du genre: '0=toto;3=truc;5=machin'

    Je voudrais interpréter ce texte sachant que chaque numéro représente un numéro de colonne.

    Pour prendre un exemple, j'ai la table suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    -----------------------
    | id |     texte      |
    -----------------------
    |  1 | 0=AA;3=BB;5=CC |
    |  2 | 1=xx;2=yy;5=zz |
    et je souhaite afficher:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    -------------------------------------
    | id | C0 | C1 | C2 | C3 | C4 | C5 |
    -------------------------------------
    |  1 | AA |    |    | BB |    | CC |
    |  2 |    | xx | yy |    |    | zz |
    Est ce que je peux rajouter des colonnes à la DBGrid (meme en laissant la colonne texte) que je renseigne moi-même par le code ?
    J'ai essayé DBGRid1.Columns.add mais ça ne marche pas, tout le contenu de la DBGrid disparait.

    Dois-je créé une TStringGrid en parallèle que je viendrais remplir par du code ?

    Il faut savoir que c'est moi qui génère le contenu du champ texte, donc si nécessaire je peux modifier son contenu.
    Pour des raisons de place je ne veux pas stocker directement les données dans des colonnes distinctes, car je peux avoir près d'un milliard d'enregistrements dans la table et je cherche à optimiser la taille de la table qui est occupée sur disque. Cette méthode est beaucoup moins gourmande en espace disque et il faut savoir qu'il n'y a pas que 5 colonnes comme dans cet exemple mais bien plus.

    Merci
    Franck

  2. #2
    Membre émérite Avatar de sergio_is_back
    Homme Profil pro
    Consultant informatique industrielle, développeur tout-terrain
    Inscrit en
    Juin 2004
    Messages
    1 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Consultant informatique industrielle, développeur tout-terrain
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 183
    Par défaut
    Deux solutions :

    1. Il faut rajouter des champs calculés à ta requête et les remplir sur l'événement OnGetText de chacun. Les champs apparaitront alors dans la DBGRID comme s'il étaient issus de ta requête

    2. Faire le prédécoupage C0, C1, C2, etc... dans ta requête SQL

  3. #3
    Membre expérimenté Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    Septembre 2004
    Messages
    516
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Septembre 2004
    Messages : 516
    Par défaut
    Merci Sergio..toujours les mêmes qui répondent :-)
    Je vais tenter de comprendre ce que tu m'as dis car même si je développe sous Delphi depuis 30 ans, je débute en base de données...il y a un début à tout.
    Je ne sais pas rajouter des champs calculés ni faire le prédécoupage dans une requête sql..je vais faire quelques recherches Google.

    EDIT
    Pour le prédécoupage dans la requête, j'ai trouvé cette solution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Select NULL as C0,NULL as C1,NULL as C2 from matable
    C'est ça dont tu parles ?

    Par contre pour les champs calculés...

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 914
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 914
    Par défaut
    Citation Envoyé par franckcl Voir le message
    je cherche à optimiser la taille de la table qui est occupée sur disque. Cette méthode est beaucoup moins gourmande en espace disque
    Permets-moi d'en douter (mais ça dépendra du nombre de colonnes et du nombre de colonnes remplies). Un champ VARCHAR prend un octet de plus (pour une chaîne de max 255 car.) que la taille de la donnée.

    Dans ton exemple (six colonnes dont trois remplies de deux caractères) c'est 12 octets alors que ton champ texte unique en demande 15.

    Sans compter que tu te prives de toutes les fonctions d'agrégation, d'indexation, de trie...

  5. #5
    Membre expérimenté Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    Septembre 2004
    Messages
    516
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Septembre 2004
    Messages : 516
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Permets-moi d'en douter (mais ça dépendra du nombre de colonnes et du nombre de colonnes remplies). Un champ VARCHAR prend un octet de plus que la taille de la donnée (1 octet si vide).
    Dans ton exemple (six colonnes dont trois remplies de deux caractères) c'est 12 octets alors que ton champ texte unique en demande 15.
    Sans compter que tu te prives de toutes les fonctions d'agrégation, d'indexation, de trie...
    Voici quelques explications supplémentaire du projet:

    Il s'agit de développer un enregistreur de données.
    Il y a environ 4000 données à enregistrer régulièrement mais ce chiffre est variable (chaque données est sous forme de texte limité à 255 caractères mais la taille moyenne est inférieure à 10 octets).
    Une ligne est ajoutée toutes les secondes mais pour économiser de la place sur disque je n'enregistre que les valeurs qui ont changées.
    Il n'y a donc qu'environ 80 valeurs par secondes qui sont enregistrées et toutes les 10 minutes, j'enregistre les 4000 données.
    Je ne peux pas créer une table qui contient 4000 colonnes (sachant aussi que le nombre de données est variable, il faudrait que je redimensionne à chaque changement)
    L'enregistreur et le stockage dans la base fonctionne parfaitement.

    Ce que je cherche maintenant c'est remettre ces données en colonnes afin de les afficher dans une grille.

  6. #6
    Membre Expert
    Avatar de ALWEBER
    Homme Profil pro
    Expert Delphi
    Inscrit en
    Mars 2006
    Messages
    1 526
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 70
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Expert Delphi

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 526
    Billets dans le blog
    10
    Par défaut
    Regarde de ce côté :
    http://www.componentace.com/calculated-field-delphi.htm
    Les colonnes sont ajoutées dans l'objet TTable ou FDTable en double-cliquant sur le composant et en ajoutant tous les champs de la table + les champs calculé que tu souhaites
    Si besoin je peux te préparer un exemple

  7. #7
    Membre expérimenté Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    Septembre 2004
    Messages
    516
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Septembre 2004
    Messages : 516
    Par défaut
    Citation Envoyé par ALWEBER Voir le message
    Regarde de ce côté :
    http://www.componentace.com/calculated-field-delphi.htm
    Les colonnes sont ajoutées dans l'objet TTable ou FDTable en double-cliquant sur le composant et en ajoutant tous les champs de la table + les champs calculé que tu souhaites
    Si besoin je peux te préparer un exemple
    Merci, je viens de faire un essai rapide sur une colonne que j'ai ajouté en double cliquant sur le composant TFDTable et en écrivant du code dans l'évènement OnCalcFields et ça marche.
    Il me reste à automatiser ça.
    Il faudrait que je puisse rajouter des colonnes dynamiquement (c'est l'utilisateur qui choisira quelles sont les colonnes qu'il veut ajouter...) mais je ne sais pas comment faire....je vais chercher.

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 914
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 914
    Par défaut
    Sans être un spécialiste de la base de données, pour moi c'est une table de trois champs : id de l'événement (ID : INT ou BIGINT), type de donnée (TypeID : SMALLINT), donnée (Data : VARCHAR) avec une ligne par mesure.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ----------------------
    | ID | TypeID | Data |
    ----------------------
    |  1 |   0    |  AA  |
    |  1 |   3    |  BB  |
    |  1 |   5    |  CC  |
    |  2 |   1    |  xx  |
    |  2 |   2    |  yy  |
    |  2 |   5    |  zz  |
    Ensuite, un pivot pour la mise en forme en colonne :
    Code sql : 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
    SELECT 
      ID, 
      MAX(D1),  
      MAX(D2),  
      MAX(D3),  
      ...
     
    FROM
        (SELECT DISTINCT
           ID,
           IF(TypeID=1, Data, NULL) AS D1,
           IF(TypeID=2, Data, NULL) AS D2,
           IF(TypeID=3, Data, NULL) AS D3,
           ...
     
         FROM MyTable
         ORDER BY ID) tmp
     
    GROUP BY ID

    Et pour avoir les dernières données des 4000 points de mesure :
    Code sql : 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
    DROP TEMPORARY TABLE if EXISTS MyTmpTable;
    CREATE TEMPORARY TABLE MyTmpTable
      SELECT DISTINCT
        ID,
        IF(TypeID=1, Data, NULL) AS D1,
        IF(TypeID=2, Data, NULL) AS D2,
        IF(TypeID=3, Data, NULL) AS D3
     
      FROM MyTable
      ORDER BY ID;
     
    SELECT (SELECT D1 FROM MyTmpTable WHERE NOT ISNULL(D1) ORDER BY ID DESC LIMIT 1),
           (SELECT D2 FROM MyTmpTable WHERE NOT ISNULL(D2) ORDER BY ID DESC LIMIT 1),
           (SELECT D3 FROM MyTmpTable WHERE NOT ISNULL(D3) ORDER BY ID DESC LIMIT 1)
     
    FROM MyTmpTable
    LIMIT 1;

  9. #9
    Membre émérite Avatar de sergio_is_back
    Homme Profil pro
    Consultant informatique industrielle, développeur tout-terrain
    Inscrit en
    Juin 2004
    Messages
    1 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Consultant informatique industrielle, développeur tout-terrain
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 183
    Par défaut
    Citation Envoyé par franckcl Voir le message
    Merci, je viens de faire un essai rapide sur une colonne que j'ai ajouté en double cliquant sur le composant TFDTable et en écrivant du code dans l'évènement OnCalcFields et ça marche.
    Il me reste à automatiser ça.
    Il faudrait que je puisse rajouter des colonnes dynamiquement (c'est l'utilisateur qui choisira quelles sont les colonnes qu'il veut ajouter...) mais je ne sais pas comment faire....je vais chercher.
    Au lieu d'utiliser TFDTable tu peux utiliser aussi TFDQuery, c'est plus souple car cela te permettra de filtrer tes requêtes

    Pour l'ajout dynamique de champs calculés à un TFDTable ou à un TFDQuery c'est relativement simple, cela peut se faire dans l'événement OnBeforeOpen de la requête ou de la table (de mémoire, à tester bien sur) :

    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
     
    procedure TForm3.FDQuery1BeforeOpen(DataSet: TDataSet);
    var
        NewField    :   TField;
    begin
        // Aujouter un champ
        NewField:=TField.Create(Self);
        NewField.DataType:=ftString;
        NewField.FieldKind:=fkCalculated;
        NewField.FieldName:='C10';
        NewField.Size:=10;
        NewField.DisplayName:='Champ C10';
        // Ajouter le champ aux champs existants de la requête
        DataSet.Fields.Add(NewField);
     
        // Aujouter un deuxième champ (un entier cadré à droite)
        NewField:=TField.Create(Self);
        NewField.DataType:=ftInteger;
        NewField.FieldKind:=fkCalculated;
        NewField.FieldName:='C11';
        NewField.Size:=10;
        NewField.DisplayName:='Champ C11';
        NewField.Alignment:=taRightJustify;
        // Ajouter le champ aux champs existants de la requête
        DataSet.Fields.Add(NewField);
     
        // etc....
    end;

  10. #10
    Membre expérimenté Avatar de franckcl
    Homme Profil pro
    Developpeur Delphi
    Inscrit en
    Septembre 2004
    Messages
    516
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Developpeur Delphi
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Septembre 2004
    Messages : 516
    Par défaut
    Merci Sergio, ça marche.
    J'ai fait quelques petites corrections et c'est bon ça marche et je vais partir sur cette solution.

    Voici le code sur l'évènement BeforeOpen
    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
     
    Procedure TForm1.FDTable1BeforeOpen(DataSet: TDataSet);
    var
      StringField :TStringField;
      IntegerField:TIntegerField;
    begin
      // Aujouter un champ
      StringField:=TStringField.Create(Self);
      //NewField.DataType:=ftString;
      StringField.FieldKind:=fkCalculated;
      StringField.FieldName:='C0';
      StringField.Size:=10;
      StringField.DisplayLabel:='Champ C0';
      // Ajouter le champ aux champs existants de la requête
      StringField.DataSet:=FDTable1;
    //  StringField.DataSet.Fields.Add(StringField);
     
      // Ajouter un deuxième champ (un entier cadré à droite)
      IntegerField:=TIntegerField.Create(Self);
      IntegerField.FieldKind:=fkCalculated;
      IntegerField.FieldName:='C1';
      //IntegerField.Size:=10;
      IntegerField.DisplayLabel:='Champ C1';
      IntegerField.Alignment:=taRightJustify;
      // Ajouter le champ aux champs existants de la requête
    //  Datasource1.DataSet.Fields.Add(IntegerField);
      IntegerField.DataSet:=FDTable1;
    end;
    Et voici le code sur l'évènement CalcFields

    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
     
    procedure TForm1.FDTable1CalcFields(DataSet: TDataSet);
    Var
      S : String;
      p : integer;
    begin
     with FDTable1 do
     Begin
       S := FieldByName('data').AsString;
       // tag 0
       if pos('0=',S)=1 then FieldByName('C0').AsString := copy(S,3,pos('`',S)-3);
       // tag 1
       p:=pos('`1=',S);
       if p>0 then FieldByName('C1').AsInteger := copy(S,p+3,posCharFrom('`',S,p+3)-p-3).ToInteger;
     End;
    end;
    Merci encore !!!
    Franck

  11. #11
    Membre émérite Avatar de sergio_is_back
    Homme Profil pro
    Consultant informatique industrielle, développeur tout-terrain
    Inscrit en
    Juin 2004
    Messages
    1 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Consultant informatique industrielle, développeur tout-terrain
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 183
    Par défaut
    Citation Envoyé par franckcl Voir le message
    Merci Sergio, ça marche.
    J'ai fait quelques petites corrections et c'est bon ça marche et je vais partir sur cette solution.
    Si ça te convient c'est parfait !
    Mais tu peux aussi essayer de tester la solution proposée par andnotor qui serait peu être plus efficace avec de gros volumes de données.
    Faut savoir que Delphi va appeler la méthode OnCalcFlieds pour chaque enregistrement de ta table, si tu viens à faire un FetchAll avec 100000 enregistrements pour un export sous Excel par exemple ça peut vite devenir extrêmement lent
    Ensuite rien ne t’emperchera de combiner les deux pour tirer partie de la souplesse de l'une et de la rapidité de l'autre...

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 28/10/2016, 22h12
  2. Comment ajouter des items à une listView
    Par colorid dans le forum Langage
    Réponses: 7
    Dernier message: 10/10/2012, 08h40
  3. Réponses: 3
    Dernier message: 18/12/2008, 15h46
  4. comment ajouter des méthodes à une classe lors Runtime?
    Par revever dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 31/03/2008, 13h53
  5. Réponses: 4
    Dernier message: 17/05/2006, 09h21

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