[Предыдущая: Соединение с базой данных] [Программирование с SQL] [Следующая: Использование классов-моделей SQL]
Выполнение инструкций 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 {
query.last();
numRows = query.at() + 1;
}
Если вы перебираете результирующую выборку только с помощью вызовов next() и seek() с положительными значениями, то можете перед вызовом exec() вызвать QSqlQuery::setForwardOnly(true). Эта небольшая оптимизация сильно ускорит выполнение запросов, возвращающих большие выборки.
Вставка, изменение и удаление записей
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();
Транзакции можно использовать для того, чтобы гарантировать атомарность сложного действия (например, просмотр внешних ключей и создание записи) или для возможности отмены сложного действия в процессе его выполнения.
[Предыдущая: Соединение с базой данных] [Программирование с SQL] [Следующая: Использование классов-моделей SQL]
Авторские права © 2010 Nokia Corporation и/или её дочерние компании |
Торговые марки |
Qt 4.6.4 |
|