Spec-Zone.ru › Qt 5.9

Использование 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 просто пересылает запрос в DBMS; в противном случае Qt имитирует синтаксис плейсхолдера путём предварительной обработки запроса. Фактический запрос, который в конечном итоге выполняется DBMS, доступен как 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.9/sql-sqlstatements.html

Spec-Zone.ru

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