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