Использование 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