Spec-Zone.ru › Qt 5.11

Выполнение 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.11/sql-sqlstatements.html

Spec-Zone.ru

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