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

Bases de données Discussion :

Ma requête SQL me retourne un QVariant invalide


Sujet :

Bases de données

  1. #1
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut Ma requête SQL me retourne un QVariant invalide
    Bonjour,

    Lors d'une requete SQL je récupère un QVariant invalide, voici mon code:

    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
    void DatabaseClass::initNewCodeP(FicheProprietaire *fichepro)
    {
         QString S;
     
     
         QSqlQuery q;
         q.prepare("SELECT MAX(codeP) FROM Proprietaire");
         q.exec();
     
         if (q.lastError().isValid()) 
         {
            qDebug() << q.lastError();
         } 
         else 
         {
            qDebug() << "requete correcte";
            QVariant v = q.value (0);
            if (v.type() == QVariant::Invalid)
            {qDebug() << "mauvais type";}
            qDebug() << S.setNum(q.value(0).toInt());
            fichepro->setCodeP(S);
         }
    }
    voici les debugs générés:
    requete correcte
    QSqlQuery::value: not positioned on a valid record
    mauvais type
    QSqlQuery::value: not positioned on a valid record
    "0"
    Ma requête SQL me semble correcte pourtant, donc tout me laisse penser que c'est la méthode value de QSqlQuery qui m'embête, et je n'ai pas trop compris le fonctionnement de cette méthode dans la doc...

    Merci d'avance de votre aide!

  2. #2
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut,

    Comme le dit le message d'erreur, tu n'es pas positionné sur un enregistrement valide. Il faut toujours faire q.first() et ensuite itérer sur les records en appelant q.next().

  3. #3
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    Salut,

    Je reposte ici car j'ai encore un problème de compréhension à ce sujet.

    Ma syntaxe doit être fausse:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
        QSqlQuery q;
        q.prepare("SELECT COUNT(codeP) FROM Proprietaire WHERE codeP = :codeP");
        q.bindValue(":codeP", v.value(0));
        if(q.lastError().isValid())
           qDebug(qPrintable(q.lastError().text()));
        if (!q.exec())
           qDebug() << "codeP n'existe pas...";
        else
           q.first();
           while (q.next())
           {qDebug()<<"bool si ligne existante ou non:";
           qDebug() <<q.value(0).toInt();}

  4. #4
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Et le problème est... ?

  5. #5
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    Que mon variant reste invalide avec le code précédent.
    Je pense que j'utilise mal next(), mais j'ai vu un exemple ou il est utilisé de la sorte, j'ai donc suivit cet exemple... (j'ai aussi essayé de l'utiliser différemment, sans itération par exemple, mais toujours rien)

    Le but est que je récupère la valeur de mon SELECT COUNT


    Merci d'avance

    PS: j'aimerai aussi savoir pour tout autre chose:
    Si j'ai plusieurs fois ":codeP" dans ma requete SQL,
    bindValue(":codeP", 1) va t-il mettre tout mes ":codeP" à 1 ou le fait-il pour un seul?

  6. #6
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Oups, mea culpa, désolé de t'avoir induit en erreur! Le first est inutile

    Exemple tiré d'un de mes codes:
    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
    	QVector<boost::shared_ptr<Product> > productSet;
     
    	QString queryStr("SELECT id FROM product WHERE sourceId=:sid");
    	QSqlQuery query;
    	query.prepare(queryStr);
    	query.bindValue(":sid", s->getId());
     
    	if(!query.exec())
    	{
    		error = QObject::tr("Can't execute statement: %1").arg(query.executedQuery());
    		return productSet;
    	}
     
    	while(query.next())
    	{
    		productSet<< boost::shared_ptr<Product>(new productSet(query.value(0).toULongLong(), s));
    	}
     
    	return productSet;

  7. #7
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Citation Envoyé par Somato Voir le message
    PS: j'aimerai aussi savoir pour tout autre chose:
    Si j'ai plusieurs fois ":codeP" dans ma requete SQL,
    bindValue(":codeP", 1) va t-il mettre tout mes ":codeP" à 1 ou le fait-il pour un seul?
    Aucune idée; j'aurais tendance à dire que oui. Mais tu penses à quoi comme requête pour utiliser ça?

  8. #8
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    A une requete du genre: je teste si codeP = 4 et si ce n'est pas le cas je mets codeP = 4

    j'appelle donc deux fois BindValue("codeP", 4) dans ma requete.

  9. #9
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Je vois pas trop l'intérêt (je vois surtout le danger ), mais soit. Essaie et tu verras; je ne peux pas te certifier que c'est bon bien que je le suppose (l'appeler une fois ou 2 ou 3 ou... ne devrait rien changer à mon avis).

  10. #10
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    L'intérêt est le suivant:
    je test si codeP == 4 dans la base existe, s'il n'existe pas, je fais une requête INSERT pour sauvegarder mes données.
    Si le test de codeP == 4 est concluant et retourne true, je fais une requête UPDATE pour sauvegarder mes données.

    Etant donné que mon IF... THEN ... ELSE ne peut pas fonctionner avec SQLite

    Mais du coup, ce sera différent: je fais le test si codeP == 4 dans un première requête avec un premier bindValue, et la sauvegarde de la data se fait dans une seconde requête.

    En tout cas, j'arrive bien à récupérer la valeur de mon QVariant maintenant, merci!

  11. #11
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Ah, ça c'est plus précis comme explication; tu as cette option:
    * faire de codeP une valeur sans doublon dans la table
    * faire un INSERT et utiliser ON CONFLICT pour faire un UPDATE au lieu de l'INSERT si le conflit d'unicité est détecté.

    Par contre, je ne sais pas comment ça va s'utiliser et je ne pourrais t'aider beacoup plus :/
    Mais à lire la doc, ça n'a pas l'air compliqué
    INSERT => http://www.sqlite.org/lang_insert.html
    clause ON CONFLICT => http://www.sqlite.org/lang_conflict.html

  12. #12
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    Désolé, le problème est maintenant réglé donc je n'ai pas eu le réflexe de passer plus tôt.

    Donc, codeP est déjà une valeur sans doublon puisque c'est la primary key de ma table.

    Ensuite, voici du coup ce que j'ai fais:

    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
        QSqlQuery q;
        q.prepare("SELECT COUNT(codeP) FROM Proprietaire WHERE codeP = :codeP");
        q.bindValue(":codeP", v.value(0));
     
        if (!q.exec())
           qDebug(qPrintable(q.lastError().text()));
        else
           while (q.next())
           {
                 if(q.value(0).toInt() == 0) //traitement des données si codeP inexistant dans database
                 {
                      QSqlQuery q2;
                      q2.prepare("INSERT INTO "//suite du code avec bindValue, etc...
                  }
                  else // traitement des données si codeP existe déjà dans la base (donc si INSERT déjà effectué)
                  {
                       QSqlQuery q2; 
                       q2.prepare("UPDATE " //suite du code avec bindValue, etc...
                  }
    Maintenant, c'est vrai que la clause "ON CONFLICT" m'intéresse beaucoup!
    Je l'étudie et la garde de coté si j'en ai l'utilité dans la suite de mon code.
    Je garde mon code actuel, pour le moment il ne me pose pas de bug apparent

  13. #13
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    Citation Envoyé par Somato Voir le message
    Je garde mon code actuel, pour le moment il ne me pose pas de bug apparent
    Et alors? La propreté du code, c'est de la réduction de risque de bug, et une localisation accélérée lorsqu'il se présente (Je le sais pour avoir fait l'erreur de ne pas garder un code propre dans les coups de bourre => ça se paye plus tard, cher.)

  14. #14
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    J'ai pas trop été "éduqué" pour identifier du code propre ou non...
    Je voulais surtout garder du code 'que je connais', car j'ai l'impression qu'une erreur SQL est plus dur à identifier qu'une erreur de programme où des qDebug peuvent un peu plus nous aiguiller sur le problème.

    Mais donc, tu ne trouve pas mon code, ici présent, propre?
    Ton avis m'intéresse, et s'il faut que je préfère une requête SQL bourrée de ligne de fonction dans un string plutôt qu'un code C++, alors je le ferrais

  15. #15
    Membre expert

    Avatar de IrmatDen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 727
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 727
    Points : 3 266
    Points
    3 266
    Par défaut
    En effet, c'est plus dur à comprendre s'il y a une erreur SQL.
    Le code serait plus propre avec la clause on conflict car il serait beaucoup plus concis, et plus rapide car tu n'as pas de check à faire avant

  16. #16
    Membre régulier
    Inscrit en
    Décembre 2007
    Messages
    239
    Détails du profil
    Informations forums :
    Inscription : Décembre 2007
    Messages : 239
    Points : 92
    Points
    92
    Par défaut
    Ok merci,
    je verrais pour faire ça se soir alors, en aparté.

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 31/12/2010, 01h07
  2. Réponses: 1
    Dernier message: 29/04/2010, 16h00
  3. Comment retourné le contraire d'une requête SQL ?
    Par arnaudperfect dans le forum Requêtes
    Réponses: 13
    Dernier message: 12/11/2007, 12h31
  4. Une Fonction SQL qui retourne le résultat d'une requête
    Par kamacho25 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 19/09/2007, 10h44
  5. [SQL] Valeur retournée par une requête...
    Par Empty_body dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 04/01/2006, 22h13

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