在《SQLite的C語言介面規範(一)》中介紹瞭如何去連線開啟資料庫,本篇部落格就介紹如何運算元據庫,本篇主要給出瞭如何執行資料庫查詢語句(Select), 然後遍歷結果集。本篇部落格就直接使用上一篇部落格封裝的開啟資料庫的方法獲取到資料庫的操作控制程式碼,然後通過這個控制程式碼來操作我們的Sqlite資料庫。今天這篇部落格中要多Cars.sqlite資料庫中的其中一個表進行Select操作。更為細節的東西請參考SQLite官網:http://www.sqlite.org 。
一.預編譯SQL語句
要想執行一條查詢的SQL語句,需要使用下面任何一個方法先預編譯成位元組碼程式。不難看出以下方法的引數都是一樣的,那麼就先挨個的介紹一下每個引數的代表什麼。
1. 引數“sqlite3 * db”, 就是我們呼叫sqlite3_open(), sqlite3_open_v2() 或者 sqlite3_open16()成功後獲取的運算元據庫的控制程式碼。資料庫連線必須沒有被關閉。
2. zSql是第二個引數, 他的編碼格式是UTF-8或UTF-16, 它就是將會被預先編譯成位元組碼的SQL語句。sqlite3_prepare() 和 sqlite3_prepare_v2()介面使用的是UTF-8編碼。sqlite3_prepare16() 和 sqlite3_prepare16_v2() 使用的是 UTF-16編碼。
3. nByte是第三個引數,說白了,它就是引數zSql字串的最大長度。如果nByte是負數,那麼zSql的長度不限,如果nByte是正數,zSql的長度則不能超過nByte的數值,超出的部分將不會被預編譯。如果nByte是0,那麼zSql將不會被預編譯。如果你之前學過C語言的話,在C語言中是沒有所謂的字串的,是一個指向字元的指標,後面跟了好多字元,以‘’結尾,這就是C語言中的字串,需要通過指標的移動來遍歷字串的,所以nByte是很有必要的。
4. *ppStmt 是預編譯語句後左邊的指標,它可以使用sqlite3_step()執行。在發生錯誤時,*ppStmt就會被設定為NULL。如果輸入的文字不是SQL語句(輸入的文字為空字串或者一行註釋)*ppStmt就會被設定為NULL。 sqlite3_finalize()負責釋放被編譯的SQL語句。
5. pzTail, 看pzTail的型別就可以看出它是指向指標的指標。pzTail指向誰的指標呢?如他不為NULL的話,它就指向預編譯SQL語句的末尾,也就是未預編譯SQL語句的首指標。
二、預編譯SQL語句例項
下面是使用sqlite3_prepare()來預編譯的一條查詢語句,在新的專案中建議使用sqlite_prepare_v2(), 他是前者的升級版。v2代表什麼意思,在上一篇部落格中進行的簡單介紹,以後如果有時間,會對VFS(虛擬檔案系統)進行詳細的介紹。
1.定義NSString型別的SQL查詢語句,如下所示:
1 2 |
//查詢資料庫 NSString * qureyInfo = @"SELECT * FROM CARBRAND"; |
2. 定義sqlite3_stmt變數來接受預編譯後的語句。
1 |
sqlite3_stmt *statement; |
3.把NSString型別 SQL語句轉成UTF-8的型別。
1 |
const char * zSql = [qureyInfo UTF8String]; |
4.呼叫sqlite3_prepare()進行預編譯,sqlite3_prepare()預編譯後會有結果狀態碼,在上一篇部落格中進行了講解,本篇部落格不做過的贅述:
1 |
int result = sqlite3_prepare(database, zSql, -1, &statement, nil); |
經過上面這些步驟就可以獲取到預編譯後的SQL語句statement,然後我們就可以通過statement做一些愛做的事情了。
三、執行預編譯後的SQL語句
執行預編譯後的SQL語句需要呼叫sqlite3_step()。 sqlite3_step() 會被一次或多次執行,由下方截圖可知,sqlite3_step()的引數就是預編譯後的語句的指標(sqlite3_stmt *)。在新的專案中推薦使用sqlite3_prepare_v2()和sqlite3_prepare16_v2()。因為要向後相容,所以之前的介面進行了保留,不過,不建議使用sqlite3_prepare()和sqlite3_prepare16()。在“v2”介面中,被返回的預編譯語句(sqlite3_stmt物件)包含了一個原始SQL語句的副本。這導致了sqlite3_step()有三種不同的表現形式。
1.如果資料庫的Schema發生變化了,之前會返回SQLITE_SCHEMA,如果使用帶v2的方法的話,sqlite3_step()將自動重新編譯SQL語句並再次嘗試執行它。因為使用v2的方法,預編譯的結果中將包含SQL原始語句。
2.當錯誤發生時,sqlite3_step()將會返回更為詳細的錯誤程式碼和擴充套件錯誤程式碼。而之前的做法是返回一個通用的錯誤結果程式碼SQLITE_ERROR,而你不得不去呼叫sqlite3_reset()方法來查詢問題。在“v2”預編譯介面中將會立即返回錯誤原因。
3.如果特定的值與WHERE子句中的條件進行繫結,這就會影響查詢結果,這個語句將會自動被重新編譯,類似於資料庫的架構改變的情況。
下方是擴充套件後的結果集:
上面說這麼多,就是一句話,在預編譯時強烈推薦使用“v2”預編譯介面,“v2”預編譯介面是升級版,功能更強大。
sqlite3_step()介面去執行預編譯後的語句,也會返回一些結果程式碼,下面介紹一些常用的結果程式碼:SQLITE_BUSY, SQLITE_DONE, SQLITE_ROW, SQLITE_ERROR或者 SQLITE_MISUSE,如果你是使用的“v2”介面進行編譯的話,將會返回更多更為詳細的結果編碼。
SQLITE_BUSY 意味著資料庫引擎無法獲得所需的資料庫鎖然後做它的工作。如果語句是commit或執行一個外部的顯式事務,你可以重試。如果的語句不是提交併且執行一個內部顯示的事務,那麼在重試之前你應該回滾事務。
SQLITE_DONE 意味著語句執行完成並且成功。沒有初次呼叫sqlite3_reset()來重置虛擬機器恢復到初始狀態,sqlite3_step()就不應該再呼叫這個虛擬機器。
SQLITE_ROW 如果正在執行的SQL語句返回任何資料, 為了便於呼叫者處理,如果有資料,返回結果就是SQLITE_ROW。再次sqlite3_step()來檢索資料的下一行。
SQLITE_ERROR 出錯的狀態,你可以呼叫sqlite3_errmsg()來檢視具體的錯誤。sqlite3_errmsg()所需引數和返回值
上面已經準備好了預編譯好的SQL語句,我們使用sqlite3_step()來執行和遍歷一下結果集,具體程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
if (result == SQLITE_OK) { NSLog(@"查詢成功"); //遍歷結果集 while (sqlite3_step(statement) == SQLITE_ROW) { int rowNum = sqlite3_column_int(statement, 0); char *rowDataOne = (char *) sqlite3_column_text(statement, 1); char *rowDataTow = (char *) sqlite3_column_text(statement, 2); NSString *nameString = [NSString stringWithUTF8String:rowDataOne]; NSString *firstLetterString = [NSString stringWithUTF8String:rowDataTow]; NSLog(@"BrandId = %d, Name = %<a href="http://www.jobbole.com/members/uz441800" data-mce-href="http://www.jobbole.com/members/uz441800">@,</a> FirstLetter = %@",rowNum , nameString, firstLetterString); } sqlite3_finalize(statement); } else { NSString *error = [NSString stringWithFormat:@"錯誤結果程式碼:%d", result]; NSLog(@"%@", error); } |
可以對上面的程式碼進行一下修改,在while迴圈語句的最後一條語句後,加上sqllite3_reset(), 那麼這個迴圈就是一個死迴圈,讀取的永遠是第一個資料。在這兒就不往上貼程式碼了。
執行結果如下:
好,今天的資料庫查詢就先到這兒,關於別的內容,會在下節部落格中進行介紹。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!