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 :

FireDac : copie d'une table à l'autre


Sujet :

Delphi

  1. #1
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut FireDac : copie d'une table à l'autre
    Bonjour,

    je patauge sans rien comprendre depuis 2 heures sur le sujet. Je ne sais pas si cela concerne en réalité FireDac. Le problème figurerait peut-être mieux dans les bases de données.

    Je copie certains enregistrements d'une table MySQL dans une table SQLite de même structure, enfin je n'en suis pas (plus) très sûr

    Le code FireMonkey/FireDac semble fonctionnel :
    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
    //  mySQLcurrentRow, SQLiteCurrentRow : TFDDatSRow;
     
           {Récupération de la structure de la table SQLite : Table de destination}
            with SQLiteQuery do begin
              SQL.Clear;
              SQL.Add('SELECT * FROM ' + aTable + ' WHERE '+ aBRV + 'ID= ' +
                     QuotedStr(arrToIns[aRow])+' LIMIT 1;');
              Open;
              Close;
            end;
     
           {Récupération des données de l'enregistrement de la table source MySQL}
            with mySQLquery do begin
              SQL.Clear;
              SQL.Add('SELECT * FROM ' + aTable + ' WHERE '+ aBRV + 'ID= ' +
                     QuotedStr(arrToIns[aRow])+' LIMIT 1;');
              Open;
              if IsEmpty then begin
                Result := eSQLerr;
                Close;
              end;
              First;
              mySQLcurrentRow := GetRow;
            end;
     
           {Copie des données}
            if Result = eNoErr then
              with sqlitequery do begin
                if not active then active := true;
                Insert;
                SQLiteCurrentRow := GetRow;
                for aCol := 0 to mysqlCurrentRow.Table.Columns.Count - 1 do
                  SQLiteCurrentRow.SetData(aCol, mysqlCurrentRow.GetData(aCol));
                Post;
              end;
    Mais je n'obtiens pas directement le résultat escompté quand les tables sont définies comme elles devraient l'être, la table MySQL ainsi :
    CREATE TABLE `users` (
    `usID` CHAR(20) NOT NULL DEFAULT '' ,
    `usNOM` VARCHAR(30) NULL DEFAULT NULL ,
    `usPRENOM` VARCHAR(30) NULL DEFAULT NULL ,
    `usLOGIN` VARCHAR(30) NULL DEFAULT NULL ,
    `usPASSWORD` VARCHAR(30) NULL DEFAULT NULL ,
    `xxSTAMP` CHAR(17) NULL DEFAULT NULL ,
    PRIMARY KEY (`usID`),
    UNIQUE INDEX `uNOM` (`usNOM`, `usPRENOM`),
    UNIQUE INDEX `uLOGIN` (`usLOGIN`, `usPASSWORD`)
    )
    COLLATE='utf8_roman_ci'
    ENGINE=InnoDB
    ROW_FORMAT=COMPACT
    ;
    alors que la table SQLite l'est ainsi :
    csCREATEusers: string = 'CREATE TABLE IF NOT EXISTS [users] (' +
    '[usID] NCHAR(20) NOT NULL,' +
    '[usNOM] VARCHAR(30) COLLATE UTF16NoCase,' +
    '[usPRENOM] VARCHAR(30) COLLATE UTF16NoCase,' +
    '[usLOGIN] NVARCHAR(30),' +
    '[usPASSWORD] NVARCHAR(30),' +
    '[xxSTAMP] NCHAR(17),' +
    'CONSTRAINT [] PRIMARY KEY ([usID]));' +
    'CREATE UNIQUE INDEX IF NOT EXISTS [uNOM] ON [users] ([usNOM], [usPRENOM]);' +
    'CREATE UNIQUE INDEX IF NOT EXISTS [uLOGIN] ON [users] ([usLOGIN], [usPASSWORD]);';
    Initialement la table MySQL a été créée avec un xxSTAMP en VARCHAR(20), bien avant que je ne porte le code de mon projet sous FMX. Puis j'ai corrigé sa structure en CHAR(17) alors que le portage était commencé, sachant que les valeurs des données de ce champ ont toujours été NULL (jamais remplies).

    La table SQLite est créée dynamiquement par Delphi. Avec [xxSTAMP] NCHAR(17) dans la table SQLite, j'obtiens alors une erreur de FireDac qui me signifie que les 2 xxSTAMP n'ont pas la même taille : [20] contre [17] . En précisant [xxSTAMP] NCHAR(20) pour la table SQLite, cela fonctionne normalement. Donc, pour FireDac, la structure de la table MySQL semble être la première définie (VARCHAR (20)) et pas celle corrigée ultérieurement (CHAR(17)). Comment expliquer cela ? J'ai appliqué sur ma table innodb un "repair". Sans effet

    Pour avoir gain de cause (avec l'écriture "normale" de définition des tables), il a fallu que je sauvegarde ma table MySQL dans une autre table avec la "bonne structure" dès le départ, détruise la première et renomme la seconde. Dans la mesure où j'ai quelques tables quand même avec le même vieux xxSTAMP, j'aurais bien aimé comprendre le problème. Maintenant compte tenu du temps passé, quelques moments de plus a les recréer ne seront pas un drame. Mais par curiosité j'aimerais comprendre le problème.

    Merci. Zac.

  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 955
    Points
    40 955
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    je ne suis pas très sur de bien comprendre le traitement mais plusieurs points me gênent

    tout d'abord ai-je bien compris ? le traitement peut se faire sur des tables de différentes structures d'où la construction de la requête, mais les tables mySQL et SQLite contiennent les mêmes noms et nombre de champs

    tout d'abord la méthode d'utilisation de la requête
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        SQL.Add('SELECT * FROM ' + aTable + ' WHERE '+ aBRV + 'ID= ' +
                QuotedStr(arrToIns[aRow])+' LIMIT 1;');
    il aurait été AMHA préférable d'utiliser paramètre et macro
    SQL.Text:='SELECT * FROM !atable WHERE !abrv LIMIT 1'; // du coup ceci peut être "fixe" dans le dfm
    MacrobyName('Atable').asraw:=atable;
    MacrobyName('ABRV').asraw:=abrv+'ID=:a';
    ParamByName('a').asString:=arrToIns[aRow]

    le limit 1 est-il vraiment nécessaire ? (surtout si iD est une clé unique)

    le first ligne 22 est inutile tout d'abord parce que en ouvrant la requête elle est automatiquement sur le 1°enregistrement et que de toute façon il n'y en a qu'un (LIMIT 1)

    passons à la copie des données, je l'aurais écrit (sans tester) ainsi

    avec le code proposé ligne 32/33, je dois avouer ne pas comprendre le pourquoi du getrow ni des variables mySQLcurrentRow et SQLiteCurrentRow
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for aCol := 0 to mysqlQuery.Fields.count - 1 do
                Fields[acol].value:=mySQLquery.Fields[acol].value;

    Autres solutions pour copier des données
    - passer par FDBatchmove (avec une petite préférence pour celle-ci qui pourrait tout faire en une passe si arrToIns[aRow] était plus explicite ?)
    - passer par FDLocalSQL
    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 du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Bonjour,

    Tu sais, j'ai passé pas mal de temps avec les Fields[acol].value:=mySQLquery.Fields[acol].value;. Je n'ai pas retenu cette solution notamment pour l'affectation des champs NULL.

    J'ai également éliminé tout ce qui fait appel à des fkData/FieldKind dans cette portion du code.

    Pour les détails :
    • le LIMIT 1. Et bien, je ne sais pas si dans le cadre d'une clé unique ou primaire, il est nécessaire ou non. Si tel n'est pas le cas, cela signifie(rait) qu'en cas de SELECT le moteur de la BDD est programmé pour ne pas parcourir le reste de la base si la clé est unique ou primaire (Quid des NULL). Déjà quand on constate les différences entre un MyISAM et un InnoDB, le doute est permis. Alors entre une InnoDB et un SQLite... Je ne sais pas si cette optimisation est intégrée ou non. Au pire LIMIT 1 est une simple redondance.
    • Le first : idem, au pire, cela ne mange pas de pain. Une habitude après un Open.

    Je crois que je vais rester sur ma curiosité. Je demandais si c'était Delphi qui avait stocké cette information initiale du VARCHAR à 20 (et où ?) ou si FireDac récupérait quelque part ( et mal) l'historique des modifications de la base sur le serveur MySQL.

    Enfin les méthodes semi-automatisées proposées, je n'en veux pas non plus : j'en sors ! Difficile le gars

    Cordialement. Zac.

Discussions similaires

  1. Copie d'une table à l'autre
    Par Marcus1 dans le forum 4D
    Réponses: 4
    Dernier message: 12/09/2013, 08h45
  2. [MySQL] Copie d'une table à l'autre + mise a jour d'un champ dans la table d'arrivée
    Par reventlov dans le forum PHP & Base de données
    Réponses: 7
    Dernier message: 28/06/2012, 15h10
  3. copie d'une table vers une autre
    Par bibile dans le forum Requêtes
    Réponses: 5
    Dernier message: 10/08/2007, 09h21
  4. Copie d'une table à une autre
    Par papipasto dans le forum Requêtes
    Réponses: 1
    Dernier message: 21/03/2006, 17h02
  5. [VB.NET] Copie d'une table d'une DB vers une autre
    Par SergeF dans le forum Windows Forms
    Réponses: 9
    Dernier message: 20/11/2004, 09h54

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