QSqlQuery


要在Qt中執行與處理SQL,可以使用QSqlQuery,假設您建立的表格如下:
create table T_USER (
     id bigint not null auto_increment,
     name varchar(255),
     age bigint,
     primary key (id)
);

您可以如下使用QSqlQuery執行SQL語句:
QSqlQuery query;
query.exec("INSERT INTO T_USER (name, age) "
                    "VALUES ('bush', 9)");

這會在指定的資料庫表格中插入一筆資料,也可以直接在建構函式中指定SQL語句,這會在建構物件之後,直接執行SQL語法:
QSqlQuery query("INSERT INTO T_USER (name, age) "
                    "VALUES ('bush', 9)");

您可以使用numRowsAffected()傳回影響的筆數,例如:
QSqlQuery query;
query.exec("DELETE FROM T_USER WHERE name = 'bee'");
cout << query.numRowsAffected() << endl;

如果要查詢資料,可以用next()方法移至所查得的下一筆資料,如果可以找到下一筆資料則傳回true,否則傳回false,例如:
QSqlQuery query;
query.exec("SELECT * FROM T_USER");
while (query.next()) {
    int id = query.value(0).toInt();
    QString name = query.value(1).toString();
    int age = query.value(2).toInt();
    cout << id << " " << qPrintable(name) << " " << age << endl;
}

value()方法中的引數,是您所指定的表格欄位順序,因為資料庫表格中所儲存的型態是未知的,value()方法傳回的是 QVariants型態的物件,QVariants在Qt中用來持有各種不同型態的資料,從基本的int到物件型態都可以,使用value()方法傳回 QVariants物件之後,再使用相關方法,如toString()、toInt()等嘗試轉為指定的型態。

除了next()方法之外,QSqlQuery還有previous()、seek()、first()、last()等方法,方便您進行資料檢索,但是 效能上負擔較重,如果您只是要循序取出資料,則可以使用QSqlQuery()的setForwardOnly()設定為true,再用next()方法 取出資料,以獲得較好的效能。

如果資料庫表格的欄位很多,直接使用字串的方式撰寫SQL時,在安插資料時就會有點麻煩,尤其是在需要正確escape某些字元時,而且對於大量資料安插時,將一些型態轉換為字串也有損效能,您可以用 prepare()方法搭配佔位字元 '?' 的方式來指定資料安插處,再使用bindValue()來指定真正要安插的資料,例如:
QSqlQuery query;
query.prepare("INSERT INTO T_USER (name, age) VALUES (?, ?)");
query.addBindValue("bee");
query.addBindValue(1);
query.exec();

這樣的寫法是ODBC風格的寫法,另一種方式則是直接指定Oracle風格的語法,可以直接指定佔位名稱,再搭配bindValue()方法指定實際值,例如:
QSqlQuery query;
query.prepare("INSERT INTO T_USER (name, age) VALUES (:name, :age)");
query.bindValue(":name", "justin");
query.bindValue(":age", 33);
query.exec();

如果資料庫支援交易(Transaction),則您可以使用Qt的交易支援,例如:
QSqlDriver *driver = QSqlDatabase::database().driver();
if (driver->hasFeature(QSqlDriver::Transactions)) {
    QSqlDatabase::database().transaction();
    QSqlQuery query;
    query.exec("INSERT .....");
    ....
    QSqlDatabase::database().commit();
}

QSqlDatabase的靜態database()方法,傳回目前資料庫連結的QSqlDatabase實例,您使用其driver()傳回驅動程式實 例,並使用hasFeature()測試是否支援交易,如果支援,則使用transaction()開啟交易,使用commit()提交執行,或使用 rollback()方法撤消。

如果需要對多個資料庫的連結,則可以使用QSqlDatabase的addDatabase()方法時指定別名,例如:
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DEMO2");
db.setHostName("localhost");
db.setDatabaseName("demo2");
db.setUserName("admin");
db.setPassword("123456");

如果要傳回該資料庫連結的QSqlDatabase實例,則在使用database()方法時指定別名,並在使用QSqlQuery時,指定傳回的QSqlDatabase實例,例如:
QSqlDatabase db = QSqlDatabase::database("DEMO2");
QSqlQuery query(db);
query.exec("....");