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

Langage Delphi Discussion :

[D7] Update avec sous-requête


Sujet :

Langage Delphi

  1. #1
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut [D7] Update avec sous-requête
    Bonjour,

    Je travaille avec Delphi 7 et SQL Server 2016.

    J'ai besoin de faire un update dans ma base de données en passant par une sous-requête.
    Les données étant saisies par un utilisateur, je voulais utiliser des paramètres.

    J'ai donc écrit le code suivant :

    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
     
    var
        qsql: TSQLQuery;
    begin
    // ...
    try
        qsql.SQL.Add('UPDATE dossier SET my_date = :pdate ');
        qsql.SQL.Add('WHERE id IN ');
        qsql.SQL.Add('(');
        qsql.SQL.Add('    SELECT TOP 1 id ');
        qsql.SQL.Add('    FROM dossier d ');
        qsql.SQL.Add('    INNER JOIN table1 t1 on d.id = t1.id_dossier ');
        qsql.SQL.Add('    INNER JOIN table2 t2 on t1.id = t2.id_t1 ');
        qsql.SQL.Add('    WHERE t2.numero = :pnumero ');
        qsql.SQL.Add(');');
     
        qsql.ParamByName('pdate').AsDateTime := aDate;
        qsql.ParamByName('pnumero').AsString := Trim(numero);
     
        qsql.ExecSQL
    finally
        FreeAndNil(qsql);
    end;
    La ligne qsql.ExecSQL me renvoie l'erreur suivante :

    SQL state: 42000, SQL Error Code: 0
    Les informations de paramètre ne peuvent provenir
    d'instruction SQL avec des requêtes de sous-sélection.
    Définissez les informations de paramètre avant de préparer la
    commande.

    La requête seule fonctionne sans erreurs quand je l'écrit directement dans SQL Server.
    Savez-vous si il y a un autre moyen de faire fonctionner ma requête ?

    Sinon, je devrais faire un select pour récupérer l'id avant de faire mon update, mais cela doublerais alors le nombre de requêtes.

    Merci de vos commentaires.

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 202
    Points : 41 443
    Points
    41 443
    Billets dans le blog
    63
    Par défaut
    Bonjour,

    DBExpress a toujours été une de mes bêtes noires (avec ADO)
    Essayez en ajoutant ligne : qsql.Prepare; en ligne 16 (avant d'affecter les valeurs des paramètres) c'est ce que semble indiquer le message d'erreur

    si ça ne fonctionne pas, vous serez obligé de définir ceux-ci "à la main" par code

  3. #3
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut
    Merci de cette réponse.

    Citation Envoyé par SergioMaster Voir le message
    Essayez en ajoutant ligne : qsql.Prepare; en ligne 16 (avant d'affecter les valeurs des paramètres) c'est ce que semble indiquer le message d'erreur
    J'avais déjà vu ce code dans mes recherches, mais qsql.Prepare; ne fonctionne pas.

    Identificateur non déclaré : 'Prepare'
    J'ai essayé qsql.Prepared := True;, mais cela ne change malheureusement rien.


    J'ai contourné le problème en faisant une première requête pour trouver mon id (ma sous-requête) puis en faisant un update sur cet id.
    Cela fait, par contre, 2 requêtes pour chaque mise à jour, ce qui n'est pas optimale.

  4. #4
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 202
    Points : 41 443
    Points
    41 443
    Billets dans le blog
    63
    Par défaut
    en ce cas il faut rajouter les trucs "à la main"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    QSQL.ParamByName('pdate').DataType := ftDateTime;
    QSQL.ParamByName('Pnumero').DataType := ftString;
    QSQL.Prepare;

  5. #5
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 879
    Points : 11 377
    Points
    11 377
    Billets dans le blog
    6
    Par défaut
    Si les deux requêtes sont préparées puis exécutées plusieurs fois (avec une nouvelle valeur de paramètre à chaque fois), le coût supplémentaire sera réduit. Et si ce n'est que très ponctuel, le surcoût des deux requêtes devrait rester minime, surtout par rapport au temps de saisie de l'utilisateur.

  6. #6
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    en ce cas il faut rajouter les trucs "à la main"
    Je viens de faire le test, mais cela me renvoie toujours la même erreur

    SQL state: 42000, SQL Error Code: 0
    Les informations de paramètre ne peuvent provenir
    d'instruction SQL avec des requêtes de sous-sélection.
    Définissez les informations de paramètre avant de préparer la
    commande.
    Citation Envoyé par tourlourou Voir le message
    Si les deux requêtes sont préparées puis exécutées plusieurs fois (avec une nouvelle valeur de paramètre à chaque fois), le coût supplémentaire sera réduit. Et si ce n'est que très ponctuel, le surcoût des deux requêtes devrait rester minime, surtout par rapport au temps de saisie de l'utilisateur.
    C'est un traitement que j'exécute entre 20 et 50 fois en lisant le contenu d'un fichier.
    C'est pas dramatique, mais c'était dans le but d'optimiser le traitement.

  7. #7
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut
    J'ai essayé le code suivant :

    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
    var
        qsql: TSQLQuery;
    begin
    // ...
    try
        qsql.SQL.Add('UPDATE dossier SET my_date = :pdate ');
        qsql.SQL.Add('WHERE id IN ');
        qsql.SQL.Add('(');
        qsql.SQL.Add('    SELECT TOP 1 id ');
        qsql.SQL.Add('    FROM dossier d ');
        qsql.SQL.Add('    INNER JOIN table1 t1 on d.id = t1.id_dossier ');
        qsql.SQL.Add('    INNER JOIN table2 t2 on t1.id = t2.id_t1 ');
        qsql.SQL.Add('    WHERE t2.numero = :pnumero ');
        qsql.SQL.Add(');');
     
        qsql.ParamByName('pdate').DataType := ftDateTime;
        qsql.ParamByName('pnumero').DataType := ftString;
     
        qsql.Prepared := True;
     
        qsql.ParamByName('pdate').AsDateTime := aDate;
        qsql.ParamByName('pnumero').AsString := Trim(numero);
     
        qsql.ExecSQL
    finally
        FreeAndNil(qsql);
    end;

  8. #8
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 202
    Points : 41 443
    Points
    41 443
    Billets dans le blog
    63
    Par défaut
    Bon, DBExpress c'est pas mon truc .

    Une idée peut-être en mettant paramcheck:=false

    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
    var
        qsql: TSQLQuery;
    begin
    // ...
    try 
        qsql.ParamCheck:=False;
        qsql.SQL.Add('UPDATE dossier SET my_date = :pdate ');
        qsql.SQL.Add('WHERE id IN ');
        qsql.SQL.Add('(');
        qsql.SQL.Add('    SELECT TOP 1 id ');
        qsql.SQL.Add('    FROM dossier d ');
        qsql.SQL.Add('    INNER JOIN table1 t1 on d.id = t1.id_dossier ');
        qsql.SQL.Add('    INNER JOIN table2 t2 on t1.id = t2.id_t1 ');
        qsql.SQL.Add('    WHERE t2.numero = :pnumero ');
        qsql.SQL.Add(');');
     
        qsql.ParamByName('pdate').DataType := ftDateTime;
        qsql.ParamByName('pnumero').DataType := ftString;
     
        qsql.Prepared := True;
     
        qsql.ParamByName('pdate').AsDateTime := aDate;
        qsql.ParamByName('pnumero').AsString := Trim(numero);
     
        qsql.ExecSQL
    finally
        FreeAndNil(qsql);
    end;
    ou encore

    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
    var
        qsql: TSQLQuery;
       AParam : TParam;
    begin
    // ...
    try 
        qsql.ParamCheck:=False;
        qsql.SQL.Add('UPDATE dossier SET my_date = :pdate ');
        qsql.SQL.Add('WHERE id IN ');
        qsql.SQL.Add('(');
        qsql.SQL.Add('    SELECT TOP 1 id ');
        qsql.SQL.Add('    FROM dossier d ');
        qsql.SQL.Add('    INNER JOIN table1 t1 on d.id = t1.id_dossier ');
        qsql.SQL.Add('    INNER JOIN table2 t2 on t1.id = t2.id_t1 ');
        qsql.SQL.Add('    WHERE t2.numero = :pnumero ');
        qsql.SQL.Add(');');
     
        AParam:=qsql.Params.AddParameter;
        AParam.Name:='pdate';
        AParam.ParamType:=TParamType.ptInput;
        AParam.DataType:=TFieldType.ftDateTime;
        AParam.Value:=aDate;
     
        AParam:=qsql.Params.AddParameter;
        AParam.Name:='pnumero';
        AParam.ParamType:=TParamType.ptInput;
        AParam.DataType:=TFieldType.ftString;
        AParam.Value:=Trim(numero);
     
        qsql.ExecSQL
    finally
        FreeAndNil(qsql);
    end;

  9. #9
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Bon, DBExpress c'est pas mon truc .
    Je vais tester cela demain.

    Là j'en ai marre ! Je viens de faire un test, mon update fonctionne correctement avec des composants ADO.
    Je ne sais pas si je pourrais les utiliser dans mon application.

    Merci pour vos réponses et conseils

  10. #10
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 202
    Points : 41 443
    Points
    41 443
    Billets dans le blog
    63
    Par défaut
    Je viens de faire un test rapide (bien sûr sur une autre base et avec un SQL moins complexe et totalement bidon )

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    UPDATE  ACHEMINEMENT a SET LAST_UPDATE=:D
    WHERE ID_PARAM=(SELECT FIRST 1 ID FROM PARAMETRES WHERE GROUPE=:G)

    ce code fonctionne
    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
     
    var AParam : TParam;
    begin
     
    SQLQuery1.Params.ClearAndResetID; // certainement inutile si le composant est créé au runtime 
     
    AParam:=SQLQuery1.Params.AddParameter;
    AParam.Name:='D';
    AParam.ParamType:=TParamType.ptInput;
    AParam.DataType:=TFieldType.ftDateTime;
    AParam.Value:=Now;
     
    AParam:=SQLQuery1.Params.AddParameter;
    AParam.Name:='G';
    AParam.ParamType:=TParamType.ptInput;
    AParam.DataType:=TFieldType.ftString;
    AParam.Value:='Général';
    SQLQuery1.Prepared:=True;
    SQLQuery1.ExecSQL;
     
    end;
    d'un autre côté celui-ci aussi
    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
    var AParam : TParam;
        qsql : TSQLQuery;
    begin
     
    qsql:=TSQLQuery.Create(self);
    try
      qsql.SQLConnection:=SQLConnection1;
      qsql.SQL.Add('UPDATE  ACHEMINEMENT a SET LAST_UPDATE=:D');
      qsql.SQL.Add('WHERE ID_PARAM=(SELECT FIRST 1 ID FROM PARAMETRES WHERE GROUPE=:G)');
      qsql.ParamCheck:=True;
      qsql.Prepared:=true;
      ShowMessage(qsql.Params.Count.tostring);
     
    //  qsql.Params.ClearAndResetID;
    //
    //  AParam:=SQLQuery1.Params.AddParameter;
    //  AParam.Name:='D';
    //  AParam.ParamType:=TParamType.ptInput;
    //  AParam.DataType:=TFieldType.ftDateTime;
    //  AParam.Value:=Now;
    //
    //  AParam:=SQLQuery1.Params.AddParameter;
    //  AParam.Name:='G';
    //  AParam.ParamType:=TParamType.ptInput;
    //  AParam.DataType:=TFieldType.ftString;
    //  AParam.Value:='Général';
      qsql.ParamByName('D').AsDateTime:=now;
      qsql.ParamByName('G').AsString:='Général';
      qsql.ExecSQL;
    finally
      qsql.Free;
    end;
    comme pour faire ces tests j'utilise la version 10.3.2 j'en conclus que c'est plus une question de version de DBExpress qu'autre chose voilà pourquoi je déteste DBExpress et ADO : les couches (dll) en plus

  11. #11
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut
    Oui, cela semble effectivement bien venir de DBExpress.
    Malheureusement avec Delphi 7, cela va être compliqué de faire autrement...

    Merci encore de ton aide.

  12. #12
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    DBExpress a toujours été une de mes bêtes noires (avec ADO)
    Je rebondis sur cette remarque que je vois régulièrement sur le forum.
    Du coup avec Delphi 7, quel est la meilleure manière d'accéder à une base de données ?

    Personnellement, à part ce sujet, je n'ai pas eu de problèmes particuliers avec ces composants.

    Nous utilisons SQL Server avec DBExpress. Vu la taille des projets, ce serait certainement compliquer de modifier, mais si cela vaut le coup, nous pourrions nous pencher sérieusement dessus.

  13. #13
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 202
    Points : 41 443
    Points
    41 443
    Billets dans le blog
    63
    Par défaut
    Citation Envoyé par oneDev Voir le message
    Je rebondis sur cette remarque que je vois régulièrement sur le forum.
    Du coup avec Delphi 7, quel est la meilleure manière d'accéder à une base de données ?
    C'est certainement dû en grande partie à mes remarques
    Pour D7 et sans y mettre un € je recommanderai lescomposants ZEOSDBO (ZeosLIB) (à jour de préférence)
    J'avais l'habitude de les utiliser avec D2010 et plutôt avec les snapshots, j'avais même commencé un tutoriel que je n'ai jamais terminé voir mon billet

  14. #14
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    220
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 220
    Points : 238
    Points
    238
    Par défaut
    OK, merci, j'ai déjà utilisé ZeosLib.

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

Discussions similaires

  1. Requète UPDATE avec sous-requète dans la même table.
    Par Selenite dans le forum Langage SQL
    Réponses: 6
    Dernier message: 16/03/2009, 15h04
  2. Requete UPDATE avec sous-requète
    Par alaingui dans le forum Requêtes et SQL.
    Réponses: 6
    Dernier message: 27/06/2008, 21h16
  3. UPDATE avec sous requête de sélection avec regroupement
    Par Maxsen dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 09/03/2008, 11h20
  4. [FB2]Update avec sous requête resultat ?
    Par AuBozon dans le forum SQL
    Réponses: 1
    Dernier message: 29/02/2008, 21h04
  5. Requête Update avec Sous-requête
    Par Yohann_x dans le forum Requêtes
    Réponses: 8
    Dernier message: 16/02/2008, 13h19

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