详细描述
QSqlQuery 类提供了一种执行和操作SQL语句的方法。
QSqlQuery 封装了从在一个 QSqlDatabase(数据库连接)上的SQL 查询(queries) 创建,导航,检索(取回) 数据的功能。它可以用来执行DML(data manipulation language)即数据操作语句,比如 select,insert,update,delete 即数据库最常用的增删改查操作语句,也可以用来执行DDL(data definition language)即数据定义语句,例如 create table。它同样可以用来执行不属于国际标准SQL的特定数据库的命令(例如,PostgreSQL的 SET DATESTYLE=ISO)。
成功执行SQL语句会设置query的状态为活跃(active),isActive() 返回true。否则query的状态被设置为不活跃(inactive)。不论哪种情况,当执行一条新的SQL语句时,查询(query) 定位在一条无效的记录上。一个活跃的query查询在值可以被检索到之前必须被导航到一条有效的记录(因此isValid()返回true)。
对于一些数据库,当你调用 commit() 或者 rollback() 时如果一个活跃的查询(query)存在select语句,那么commit(事务)或者rollback(回滚)将会失败。
可以通过以下函数去访问查询到的数据库记录:next();previous();first();last();seek()。这些函数允许程序员向前,向后或者任意地访问query返回的记录。如果你只需要向前访问结果集(比如使用next()),你可以使用 setForwardOnly() ,这将节省大量的内存开销并提高某些数据库的性能。一旦一个活跃的查询被定位在一条有效的记录上,可以通过value()函数检索数据。所有数据都是使用QVariants数据类型从SQL 后台传输的。
举个例子:
//查询之前记得先打开数据库连接。。。
QSqlQuery query("SELECT country FROM artist");
while (query.next()) {
QString country = query.value(0).toString();
doSomething(country);
}
使用value(int)可以访问到query对象返回的数据。 由SELECT语句返回的数据中的每个字段都是通过在语句中传递字段的位置来访问的,从0开始。这使得使用SELECT *查询是不明智的,因为返回的字段的顺序是不确定的。
出于效率考虑,没有通过字段名访问字段内容的函数,除非你使用带名字的prepared queries(可是明明有QVariant QSqlQuery::value(const QString & name) const,。可能这个重载函数是在后面加入的,而当前的文档是还没加入这个重载函数的时候写的),使用record().indexOf()可以将一个字段名转换成对应的索引,例如:
QSqlQuery query("SELECT * FROM artist");
int fieldNo = query.record().indexOf("country");
while (query.next()) {
QString country = query.value(fieldNo).toString();
doSomething(country);
}
QSqlQuery支持准备查询执行(prepared query execution)和将参数值绑定到占位符。一些数据库不支持这些特性,对于那些不支持的,Qt模拟了所需的功能。例如,Oracle和ODBC支持准备查询(prepared query),Qt使用支持的这种特性;但对于不支持这种特性的数据库,Qt自己实现了这些特性,比如说,当执行一条查询通过实际值去代替占位符。使用numRowsAffected() 找出多少条非查询(non-SELECT)查询生效,使用size()去找出由SELECT查找出的数量。
Oracle数据库通过 ‘冒号字段名’ 来识别占位符,例如 :‘:name’.ODBC简单地使用了 ? 字符。这两种语法Qt都支持,限制条件是你不能在同一个查询中混合使用这两种语法。
你可以使用QMap
QMapIterator i(query.boundValues());
while (i.hasNext()) {
i.next();
cout << i.key().toUtf8().data() << ": "
<< i.value().toString().toUtf8().data() << endl;
}
等价于:
QList list = query.boundValues().values();
for (int i = 0; i < list.size(); ++i)
cout << i << ": " << list.at(i).toString().toUtf8().data() << endl;
1、使用命名占位符命名的绑定:
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (:id, :forename, :surname)");
query.bindValue(":id", 1001);
query.bindValue(":forename", "Bart");
query.bindValue(":surname", "Simpson");
query.exec();
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (:id, :forename, :surname)");
query.bindValue(0, 1001);
query.bindValue(1, "Bart");
query.bindValue(2, "Simpson");
query.exec();
3、使用位置占位符绑定值(版本1):
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (?, ?, ?)");
query.bindValue(0, 1001);
query.bindValue(1, "Bart");
query.bindValue(2, "Simpson");
query.exec();
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (?, ?, ?)");
query.addBindValue(1001);
query.addBindValue("Bart");
query.addBindValue("Simpson");
query.exec();
将值绑定到存储过程(procedure):
这段代码调用了一个名叫AsciiToInt()的存储过程,通过参数传递一个字符,并将其结果输出到out参数中。
QSqlQuery query;
query.prepare("CALL AsciiToInt(?, ?)");
query.bindValue(0, "A");
query.bindValue(1, 0, QSql::Out);
query.exec();
int i = query.boundValue(1).toInt(); // i is 65
QSqlQuery q;
q.prepare("insert into myTable values (?, ?)");
QVariantList ints;
ints << 1 << 2 << 3 << 4;
q.addBindValue(ints);
QVariantList names;
names << "Harald" << "Boris" << "Trond" << QVariant(QVariant::String);
q.addBindValue(names);
if (!q.execBatch())
qDebug() << q.lastError();
1 Harald 2 Boris 3 Trond 4 NULL