Spec-Zone.ru › Qt 5.13

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

Spec-Zone.ru

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