Использование 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 Core, такие как 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-6.2/sql-sqlstatements.html