Qt:QSqlQuery


0、說明

QSqlQuery提供了執行SQL代碼的方法。

QSqlQuery封裝了在QSqlDatabase中查詢、檢索數據的相關函數。它可以用來執行如SELECT、INSERT、UPDATE、DELETE等方法,也可以執行如CREATE TABLE等語句。

順利執行SQL語句后,調用isActive()就會返回true。一個激活的Query一定會產生一個合法的記錄(isValid()返回true),從這個記錄中可以提取到需要的數據。

對某些數據庫而言,如果有一個諸如SELECTQuery激活狀態,那么當我們調用commit()、rollback()時,相關事務操作會失敗。

歷史查詢記錄可以通過如下函數進行查詢:

next()、previous()、first()、last()、seek()

這些函數允許編輯器隨意瀏覽上一個、下一個、任意一個查詢記錄。如果我們只需要往后查看結果(調用next()),那么可以調用setForwardOnly(),這樣相比隨機存儲就可以存儲大量信息,並且提高查詢效率。

一旦一個激活的Query返回了一個合法記錄,可以通過value()來提取其中的數據。所有SQL查詢到的數據都是QVariant類型。

Query成功后,每個Query都是一條記錄(即一行),可以用while(query.next())來實現查詢每行的目的,每條記錄有多少個value是與SELECT語句中的查詢項數相關的,通過value(i)查詢對應的項,每次查詢到的值都是QVariant類型,通過QVarianttoT()方法轉換為對應的類型(這里T是泛型而不是實際類型),具體見QVaraint官方文檔

例如:

    QSqlQuery query("SELECT country FROM artist");
    while(query.next()){
        QString country = query.value(0).toString();
        doSomething(country);
    }

為了訪問Query得到的數據,可以使用value( int )方法。Query的結果數據中,索引是從0開始的,因此調用SELECT *進行查詢是不可用的,因為返回順序是不確定的。

為了提高效率,不存在通過name訪問數據的方法(除非預先在SELECT語句中通過names進行查詢)。為了將數據name轉換為索引,需要使用record().indexOf(),例如:

    QSqlQuery query(SELECT * FROM artist);
    int fieldNo = query.record().indexOf("country");
    while(query.next()){
        QString country = query.value(fieldNo).toString;
        doSomething(country);
    }

調用numRowsAffected()可以知道有多少行是被非SELECT查詢影響,調用size()可以知道有多少行是被SELECT查詢影響的。

 

需要注意的是,在創建QSqlQuery之前,必須先加載SQL Driver並且構建連接。此外,當Query存在時,連接必須維持open狀態,否則QSqlQuery的行為將不會執行。

預定義查詢與帶占位符的查詢

預定義查詢:事先定義好查詢語句,但暫時並不執行,通常是因為其中的項沒有設置,通常與占位符結合使用;

什么是帶占位符的查詢呢?就是在查詢語句中,並不把語句寫完整,而是某些地方填入占位符后,之后把占位符補充完整,就構成了一個完整的查詢。就像下邊這樣:

    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();

幾種占位符查詢的方式:

①name占位符與name填充

    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();

②name占位符與pos填充

    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();

③?占位符與pos填充

    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();

 

1、模塊和載入項

Header: #include <QSqlQuery>
qmake: QT += sql

2、構造

QSqlQuery(QSqlQuery other) 構造一個Query的副本
QSqlQuery(QSqlDatabase db) 在db上構造一個Query,如果db不存在則用默認db
QSqlQuery(QString query = QString(), QSqlDatabase db = QSqlDatabase())

用query和db構造一個Query,其中query是SQL語句對應的字符串

如果db為空或者非法,會使用默認db,如果query非空,那么在構造之后它會被執行

QSqlQuery(QSqlResult *result) 用某個查詢結果QSqlResult構造一個QSqlQuery

 

3、靜態字段

類型

字段

取值

說明

enum BatchExecutionMode { ValuesAsRows, ValuesAsColumns }  

 

Constant Value Description
QSqlQuery::ValuesAsRows 0 - Updates multiple rows. Treats every entry in a QVariantList as a value for updating the next row.
QSqlQuery::ValuesAsColumns 1 - Updates a single row. Treats every entry in a QVariantList as a single value of an array type.

4、成員方法

返回值類型

方法

說明

QSqlQuery & operator=(QSqlQuery other) 賦值
void addBindValue(QVariant val, QSql::ParamType paramType = QSql::In) 用於第四種情況的?占位符
int at()

返回當前查詢到的記錄的索引,第一個記錄的索引為0

失敗時返回一個負數

void

bindValue(QString placeholder, QVariant val, QSql::ParamType paramType = QSql::In)

bindValue(int pos,QVariant val, QSql::ParamType paramType = QSql::In)

①、②、③中占位符,第一個參數是占位符,第二個參數是它的值

QVariant

QVariant

QMap<QString, QVariant>

boundValue(QString placeholder)

boundValue(int pos)

boundValues()

返回占位符對應的值

返回占位符及其值構成的QMap<QString , QVariant>

void clear() 清除result集合,釋放該Query占有的資源。設置Query狀態為非激活,我們幾乎不需要調用該方法。
QSqlDriver * driver() 該Query相關的driver
bool

exec(QString query)

參數是一個SQL Query語句執行該語句。

Query成功時返回true,並設置query為激活狀態。

當Query執行后,需要不斷調用next()來讓該Query定位到一個合法的記錄處,之后才能提取數據。

當調用exec()時,該Query的last error將被重置。

例子:

    QSqlQuery query;
    query.exec("INSERT INTO employee (id, name, salary) "
               "VALUES (1001, 'Thad Beaumont', 65000)");
bool 

exec()

執行用prepare()預定義的查詢語句,成功時返回true。

執行時會重置該query的last error。

bool execBatch(QSqlQuery::BatchExecutionMode mode = ValuesAsRows)

 

QString executedQuery()

返回上一次成功執行的Query String。

如果是帶占位符的預定義查詢,會在占位符處填充真實值。

void finish()

告訴Driver不需要再從Query中查詢數據了。

通常不需要調用該方法,但是在重用該Query前調用該方法會釋放資源以保證資源安全。

設置Query為非激活狀態,占位符綁定的值將會維持不變。

bool first()  

提取Query結果的第一條記錄,並將Query定位到該條記錄上。

Query結果必須是激活狀態,並且isSelect()必須返回true,之后才能調用該方法,否則將會返回false並不做任何事情。

bool isActive()

如果Query是激活狀態則返回true。激活的Query是指成功調用了exec()並且沒有調用finish()之前的Query。

完成查詢之后,可以通過finish()clear()修改Query為非激活狀態,或者也能直接刪除該QSqlQuery實例。

在提交、回滾事務之前,必須用以上方法來使Query變為非激活狀態。

bool isForwardOnly() 如果只能在結果集中向前單向查詢,返回true。
bool

isNull(int field)

isNull(QString name)

以下幾種情況返回true:1、Query未激活;2、Query未定位到一個合法記錄上;3、結果上沒有指定field;4、field是null。
bool isSelect() 如果當前Query是SELECT語句返回true
bool isValid() 如果當前Query定位到一個合法記錄上,返回true
bool last() 定位當前Query到最后一條記錄上。
QSqlError lastError() 返回該Query最近的錯誤信息
QVariant lastInsertId()

返回最近插入行對應的object ID。

失敗時返回一個非法的QVariant。

如果一次插入了多行,結果將是Undefined。

QString lastQuery() 返回上一次查詢語句,如果沒有則返回空String。
bool next()

定位到查詢結果的下一條記錄上。

以下規則將會應用:

①如果當前定位到第一條記錄之前——常用於執行后立即查詢,那么結果會使Query定位到第一條記錄;

②如果定位到最后一條記錄,那么什么都不做並返回false;

③如果定位到中間,則定位到下一條記錄。

bool nextResult() 刪除當前記錄並定位到下一條記錄上。
int numRowsAffected()

返回SQL語句將會影響的行數,不確定時返回-1。

如果是SELECT語句,不能用該方法,應該用size()

Query未激活時返回-1。

QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() 返回當前的數字精度策略。 
bool prepare(QString query) 預定義查詢。
bool previous() 定位當前Query為上一條記錄。
QSqlRecord record()

返回當前Query的結果QSqlRecord,其中包含了Query結果的字段信息

如果Query指向一個合法的行,那么QSqlRecord將用指定行值填充,當Query未激活時,會返回一個空的記錄。

為了從Query中提取值,調用基於索引value()進行檢索將會速度更快。

下邊的例子中,使用了SELECT * FROM查詢語句。由於結果列的順序並不確定,所以通過QSqlRecord::indexOf()來獲取這些列的索引:

QSqlQuery q("select * from employees");
QSqlRecord rec = q.record();

qDebug() << "Number of columns: " << rec.count();

int nameCol = rec.indexOf("name"); // index of the field "name"
while (q.next())
    qDebug() << q.value(nameCol).toString(); // output all names
QSqlResult * result() 返回該Query的Result
bool seek(int index, bool relative = false) 定位到指定記錄處,第二個參數指定相對、絕對偏移,即以當前位置為基准還是以開頭為基准。
void setForwardOnly(bool forward)

只允許前向查詢。當forward為true時,next()、seek()方法只能用正數。

這個方法應當在Query exec前主動調用,默認情況下前向查詢是未激活的。

void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy) 設置數值精度
int size()

返回查詢結果的size,即行數。失敗時返回-1。

非SELECT語句會返回-1,應該調用numRowsAffected()

QVariant

value(int index)

value(QString name)

返回當前記錄中,索引字段index的值,一個字段就是一列,索引從0開始。不推薦使用SELECT *因為字段順序會被打亂。失敗時返回一個非法QVariant。

用列名的方式訪問當前記錄中某個字段的值。

7、用法

1)在某個已經openQSqlDatabase連接上構造QSqlQuery對象,方便后續查詢:

QSqlQuery query(db);//db是QSqlDatabase且已經Open

2)構造SQL語句QString,進行查詢:

    QSqlQuery query(db);
    QString sql = "SELECT str.id,str.imei,str.table_name,";
    sql+="sed.location_x,sed.location_y ";
    sql+="FROM sensor_table_relation str , sensor_end_data sed ";
    sql+="WHERE str.imei = sed.imei ";
    sql+="ORDER BY str.id";
    query.exec(sql);

3)看看一共查詢到了多少項:

如果用SELECT 列名1,列名2,...查詢,用size()

如果用SELECT *查詢,應當用numRowsAffected()

    qDebug()<<query.size();//68

4)不斷地提取某條記錄的所有字段:

在上文中,我們SELECT了5項:

  • str.id
  • str.imei
  • str.table_name
  • sed.location_x
  • sed.location_y

可以用value(i)的方式提取每條記錄中的每項,一共5項,那么i的取值就為0~4,跟這5項一一對應。需要注意的是value(i)提取的項是QVariant類型,要用toT()轉化為指定的Qt類型。

不斷地調用next(),可以依次將QSqlQuery定位到下一條記錄上,結合value(i),就能實現提取所有查找記錄的所有項的功能:

while(query.next()){
    QString imei = query.value(1).toString();
    QString table_name = query.value(2).toString();
    float locationX = query.value(3).toFloat();
    float locationY = query.value(4).toFloat();
    
    Info info( imei , table_name , locationX , locationY);//自定義存儲查詢結果的類,類似於Java中的ORM機制
    infolist.append(info);//把所有記錄存入一個QList<Info>中
}

 注意:查詢完畢后,query並沒有指向返回的第一條記錄處,需要先調用next()才能正確訪問第一條記錄的各項(這點十分重要)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM