Sur cette page

Exécution des instructions SQL

La classe QSqlQuery fournit une interface pour l'exécution des instructions SQL et la navigation dans l'ensemble des résultats d'une requête.

Les classes QSqlQueryModel et QSqlTableModel décrites dans la section suivante fournissent une interface de plus haut niveau pour l'accès aux bases de données. Si vous n'êtes pas familiarisé avec le langage SQL, vous pouvez passer directement à la section suivante(Utilisation des classes du modèle SQL).

Exécution d'une requête

Pour exécuter une requête SQL, il suffit de créer un objet QSqlQuery et d'appeler QSqlQuery::exec() comme suit :

    QSqlQuery query;
    query.exec("SELECT name, salary FROM employee WHERE salary > 50000");

Le constructeur QSqlQuery accepte un objet facultatif QSqlDatabase qui spécifie la connexion à la base de données à utiliser. Dans l'exemple ci-dessus, nous ne spécifions aucune connexion, c'est donc la connexion par défaut qui est utilisée.

En cas d'erreur, exec() renvoie false. L'erreur est alors disponible sous la forme de QSqlQuery::lastError().

QSqlQuery permet d'accéder à l'ensemble des résultats un enregistrement à la fois. Après l'appel à exec(), le pointeur interne de QSqlQuery est situé une position avant le premier enregistrement. Nous devons appeler QSqlQuery::next() une fois pour accéder au premier enregistrement, puis next() à plusieurs reprises pour accéder aux autres enregistrements, jusqu'à ce qu'il renvoie false. Voici une boucle typique qui parcourt tous les enregistrements dans l'ordre :

   while (query.next()) { QString name = query.value(0).toString() ; int salary = query.value(1).toInt() ;        qDebug() << name << salary;
    }

La fonction QSqlQuery::value() renvoie la valeur d'une rubrique de l'enregistrement en cours. Les champs sont spécifiés sous forme d'index à base zéro. QSqlQuery::value() renvoie un QVariant, un type qui peut contenir divers types de données C++ et Qt Core tels que int, QString, et QByteArray. Les différents types de base de données sont automatiquement mis en correspondance avec l'équivalent Qt le plus proche. Dans l'extrait de code, nous appelons QVariant::toString() et QVariant::toInt() pour convertir les variantes en QString et int.

Pour une vue d'ensemble des types recommandés pour une utilisation avec les bases de données supportées par Qt, veuillez vous référer à ce tableau.

Vous pouvez naviguer dans l'ensemble de données en utilisant QSqlQuery::next(), QSqlQuery::previous(), QSqlQuery::first(), QSqlQuery::last() et QSqlQuery::seek(). L'index de la ligne actuelle est renvoyé par QSqlQuery::at(), et le nombre total de lignes dans l'ensemble de résultats est disponible sous QSqlQuery::size() pour les bases de données qui le prennent en charge.

Pour déterminer si un pilote de base de données prend en charge une fonctionnalité donnée, utilisez QSqlDriver::hasFeature(). Dans l'exemple suivant, nous appelons QSqlQuery::size() pour déterminer la taille d'un ensemble de résultats si la base de données sous-jacente prend en charge cette fonctionnalité ; sinon, nous naviguons jusqu'au dernier enregistrement et utilisons la position de la requête pour nous indiquer le nombre d'enregistrements.

    QSqlQuery query;
    int numRows;
    query.exec("SELECT name, salary FROM employee WHERE salary > 50000");

    QSqlDatabase defaultDB = QSqlDatabase::database();
    if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) {
        numRows = query.size();
    } else {
        // this can be very slow
        query.last();
        numRows = query.at() + 1;
    }

Si vous naviguez dans un ensemble de résultats et que vous utilisez next() et seek() uniquement pour naviguer vers l'avant, vous pouvez appeler QSqlQuery::setForwardOnly(true) avant d'appeler exec(). Il s'agit d'une optimisation simple qui accélère considérablement la requête lorsque vous utilisez des ensembles de résultats volumineux.

Insertion, mise à jour et suppression d'enregistrements

QSqlQuery peut exécuter des instructions SQL arbitraires, et pas seulement SELECTs. L'exemple suivant insère un enregistrement dans une table à l'aide de INSERT:

    QSqlQuery query;
    query.exec("INSERT INTO employee (id, name, salary) "
               "VALUES (1001, 'Thad Beaumont', 65000)");

Si vous souhaitez insérer de nombreux enregistrements en même temps, il est souvent plus efficace de séparer la requête des valeurs réellement insérées. Pour ce faire, il est possible d'utiliser des espaces réservés. Qt supporte deux syntaxes de placeholder : named binding et positional binding. Voici un exemple de liaison nommée :

    QSqlQuery query;
    query.prepare("INSERT INTO employee (id, name, salary) "
                  "VALUES (:id, :name, :salary)");
    query.bindValue(":id", 1001);
    query.bindValue(":name", "Thad Beaumont");
    query.bindValue(":salary", 65000);
    query.exec();

Voici un exemple de liaison positionnelle :

    QSqlQuery query;
    query.prepare("INSERT INTO employee (id, name, salary) "
                  "VALUES (?, ?, ?)");
    query.addBindValue(1001);
    query.addBindValue("Thad Beaumont");
    query.addBindValue(65000);
    query.exec();

Les deux syntaxes fonctionnent avec tous les pilotes de base de données fournis par Qt. Si la base de données supporte la syntaxe de manière native, Qt transmet simplement la requête au SGBD ; sinon, Qt simule la syntaxe de l'espace réservé en prétraitant la requête. La requête réelle qui est exécutée par le SGBD est disponible à l'adresse QSqlQuery::executedQuery().

Lorsque vous insérez plusieurs enregistrements, vous ne devez appeler QSqlQuery::prepare() qu'une seule fois. Ensuite, vous appelez bindValue() ou addBindValue() suivi de exec() autant de fois que nécessaire.

Outre les performances, l'un des avantages des espaces réservés est que vous pouvez facilement spécifier des valeurs arbitraires sans avoir à vous soucier de l'échappement des caractères spéciaux.

La mise à jour d'un enregistrement est similaire à son insertion dans une table :

    QSqlQuery query;
    query.exec("UPDATE employee SET salary = 70000 WHERE id = 1003");

Vous pouvez également utiliser la liaison nommée ou positionnelle pour associer des paramètres à des valeurs réelles.

Enfin, voici un exemple d'instruction DELETE:

    QSqlQuery query;
    query.exec("DELETE FROM employee WHERE id = 1007");

Transactions

Si le moteur de base de données sous-jacent prend en charge les transactions, QSqlDriver::hasFeature(QSqlDriver::Transactions) renverra un résultat positif. Vous pouvez utiliser QSqlDatabase::transaction() pour lancer une transaction, suivie des commandes SQL que vous souhaitez exécuter dans le contexte de la transaction, puis QSqlDatabase::commit() ou QSqlDatabase::rollback(). Lorsque vous utilisez des transactions, vous devez lancer la transaction avant de créer votre requête.

Exemple :

    QSqlDatabase::database().transaction();
    QSqlQuery query;
    query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
    if (query.next()) {
        int employeeId = query.value(0).toInt();
        query.exec("INSERT INTO project (id, name, ownerid) "
                   "VALUES (201, 'Manhattan Project', "
                   + QString::number(employeeId) + ')');
    }
    QSqlDatabase::database().commit();

Les transactions peuvent être utilisées pour s'assurer qu'une opération complexe est atomique (par exemple, la recherche d'une clé étrangère et la création d'un enregistrement), ou pour fournir un moyen d'annuler une modification complexe en cours de route.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.