Spec-Zone.ru › Qt 5.6

Использование SQL-запросов

Класс QSqlQuery предоставляет интерфейс для выполнения SQL-запросов и навигации по результатам запроса.

Классы QSqlQueryModel и QSqlTableModel, описанные в следующем разделе, предоставляют интерфейс более высокого уровня для доступа к базам данных. Если вы не знакомы с SQL, можете перейти непосредственно к следующему разделу (Использование классов SQL-модели).

Выполнение запроса

Для выполнения SQL-запроса просто создайте объект QSqlQuery и вызовите QSqlQuery::exec() следующим образом:

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

Конструктор QSqlQuery принимает необязательный объект QSqlDatabase, который указывает, какую базу данных использовать. В приведенном выше примере мы не указываем никакой подключения, поэтому используется подключение по умолчанию.

Если произошла ошибка, exec() возвращает false. Ошибка затем доступна как QSqlQuery::lastError().

Навигация по набору результатов

QSqlQuery предоставляет доступ к набору результатов по одному записям за раз. После вызова exec() внутренний указатель QSqlQuery находится на позиции перед первой записью. Мы должны вызвать QSqlQuery::next() один раз, чтобы перейти к первой записи, а затем next() повторно, чтобы получить доступ к другим записям, пока не вернется false. Вот типичный цикл, который итерирует по всем записям в порядке:

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

Функция QSqlQuery::value() возвращает значение поля в текущей записи. Поля указываются как индексы с нулевым началом. QSqlQuery::value() возвращает QVariant, тип, который может хранить различные типы данных C++ и Qt, такие как int, QString и QByteArray. Различные типы баз данных автоматически отображаются на ближайшие эквиваленты Qt. В фрагменте кода мы вызываем QVariant::toString() и QVariant::toInt() для преобразования вариантов в QString и int.

Для обзора рекомендуемых типов для использования с поддерживаемыми Qt базами данных, пожалуйста, обратитесь к этой таблице.

Вы можете перемещаться вперед и назад, используя QSqlQuery::next(), QSqlQuery::previous(), QSqlQuery::first(), QSqlQuery::last() и QSqlQuery::seek(). Текущий индекс строки возвращается QSqlQuery::at(), а общее количество строк в наборе результатов доступно как QSqlQuery::size() для баз данных, которые это поддерживают.

Чтобы определить, поддерживает ли драйвер базы данных данную функцию, используйте QSqlDriver::hasFeature(). В следующем примере мы вызываем QSqlQuery::size() для определения размера набора результатов базовой базы данных, которая поддерживает эту функцию; в противном случае мы перемещаемся к последней записи и используем позицию запроса, чтобы узнать, сколько записей там есть.

    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;
    }

Если вы проитерируетесь по набору результатов, используя только next() и seek() с положительными значениями, вы можете вызвать QSqlQuery::setForwardOnly(true) перед вызовом exec(). Это простая оптимизация, которая значительно ускорит запрос при работе с большими наборами результатов.

Вставка, обновление и удаление записей

QSqlQuery может выполнять произвольные SQL-запросы, а не только SELECT. Следующий пример вставляет запись в таблицу, используя INSERT:

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

Если вы хотите вставить много записей одновременно, часто эффективнее отделить запрос от фактических значений, которые вставляются. Это можно сделать, используя плейсхолдеры. Qt поддерживает два синтаксиса плейсхолдеров: именованную привязку и позиционную привязку. Вот пример именованной привязки:

    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();

Вот пример позиционной привязки:

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

Оба синтаксиса работают со всеми драйверами баз данных, предоставляемыми Qt. Если база данных поддерживает синтаксис нативно, Qt просто перенаправляет запрос в СУБД; в противном случае Qt моделирует синтаксис плейсхолдера, предварительно обрабатывая запрос. Фактический запрос, который в конечном итоге выполняется СУБД, доступен как QSqlQuery::executedQuery().

При вставке нескольких записей вам нужно вызвать QSqlQuery::prepare() только один раз. Затем вы вызываете bindValue() или addBindValue(), за которым следует exec(), столько раз, сколько необходимо.

Помимо производительности, одним из преимуществ плейсхолдеров является то, что вы можете легко указать произвольные значения, не беспокоясь о необходимости экранирования специальных символов.

Обновление записи аналогично вставке в таблицу:

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

Вы также можете использовать именованную или позиционную привязку для связывания параметров с фактическими значениями.

Наконец, вот пример оператора DELETE:

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

Транзакции

Если базовая система управления базами данных поддерживает транзакции, QSqlDriver::hasFeature(QSqlDriver::Transactions) вернёт true. Вы можете использовать QSqlDatabase::transaction() для начала транзакции, затем последовательно выполнить необходимые SQL-команды в контексте транзакции, и после этого либо QSqlDatabase::commit(), либо QSqlDatabase::rollback(). При использовании транзакций необходимо начать транзакцию до создания запроса.

Пример:

    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();

Транзакции можно использовать для обеспечения атомарности сложной операции (например, поиска внешнего ключа и создания записи) или для предоставления способа отмены сложного изменения в середине.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/archives/qt-5.6/sql-sqlstatements.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API