swift sqlite 使用

導入 libsqlite3.0.tdb sql

建立 Header.h 並配置到 Object-C Bridging Header 數據庫

在header.h中導入sqliteswift

#import "SQLite3.h"

而後就可使用 sqlite 數據庫了數組

 

//ide

//  ViewController.swift函數

//測試


import UIKitspa


class ViewController: UIViewController {3d


    

    override func viewDidLoad() {指針

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        

    }


    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }


    

    var db: COpaquePointer = nil

    

    ///  打開數據庫  是否打開成功

    func openDatabase() -> Bool {

        

        let doc = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)

        

        let dbname = "test.db"

        let path = doc.first! + "/" + dbname

        

        let fm = NSFileManager.defaultManager()

        

        let find = fm.fileExistsAtPath(path)

        

        print("find = \(find) path = \(path)")

        

        // 若是數據庫存在,則用sqlite3_open直接打開(不要擔憂,若是數據庫不存在sqlite3_open會自動建立)

        // sqlite3_open 若是若是數據庫不存在,會新建數據庫文件

        // 若是數據庫文件已經存在,就直接打開,返回句柄,不會對數據有任何影響

        if sqlite3_open(path, &db) == SQLITE_OK {

            print("打開數據庫成功")

            // 本質上只須要運行一次就能夠了

            if createTable() {

                print("創表成功")

                // TODO: 測試查詢數據

                let sql = "SELECT id, DepartmentNo, Name FROM T_Department;"

                recordSet(sql)

            } else {

                print("創表失敗")

            }

            return true

        } else {

            print("打開數據庫失敗")

            sqlite3_close(db)

            return false

        }

    }

    ///  建立數據表,將系統須要的數據表,一次性建立

    private func createTable() -> Bool {

        // 準備全部數據表的 SQL

        // 1> 每個 SQL 完成後都有一個 ;

        // 2> 將全部創表 SQL 寫在一塊兒,每個換行添加一個 \n

        let sql = "CREATE TABLE \n" +

            "IF NOT EXISTS T_Department (\n" +

            "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" +

            "DepartmentNo CHAR(10) NOT NULL DEFAULT '',\n" +

            "Name CHAR(50) NOT NULL DEFAULT '' \n" +

            "); \n" +

            "CREATE TABLE IF NOT EXISTS T_Employee ( \n" +

            "'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, \n" +

            "'name' TEXT NOT NULL, \n" +

            "'age' INTEGER NOT NULL, \n" +

            "'department_id' INTEGER, \n" +

            "CONSTRAINT 'FK_DEP_ID' FOREIGN KEY ('department_id') REFERENCES 'T_Department' ('id') \n" +

        ");"

        

        var stmt:COpaquePointer = nil

        

        //sqlite3_prepare_v2 接口把一條SQL語句解析到statement結構裏去. 使用該接口訪問數據庫是當前比較好的的一種方法

        //第一個參數跟前面同樣,是個sqlite3 * 類型變量,

        //第二個參數是一個 sql 語句。

        //第三個參數我寫的是-1,這個參數含義是前面 sql 語句的長度。若是小於0sqlite會自動計算它的長度(把sql語句當成以\0結尾的字符串)。

        //第四個參數是sqlite3_stmt 的指針的指針。解析之後的sql語句就放在這個結構裏。

        //第五個參數是錯誤信息提示,通常不用,nil就能夠了。

        //若是這個函數執行成功(返回值是 SQLITE_OK statement 不爲NULL ),那麼下面就能夠開始插入二進制數據。

        let sqlReturn = sqlite3_prepare_v2(db, sql, -1, &stmt, nil);

        

        

        //若是SQL語句解析出錯的話程序返回

        if(sqlReturn != SQLITE_OK) {

            return false;

        }

        

        //執行SQL語句

        let success = sqlite3_step(stmt);

        //釋放sqlite3_stmt

        sqlite3_finalize(stmt);

        

        //執行SQL語句失敗

        if ( success != SQLITE_DONE) {

            return false

        }

        return true

        

    }

    

    ///  執行沒有返回值的 SQL 語句

    ///

    ///  :param: sql SQL 字符串

    ///

    ///  :returns: 是否成功

    func execSQL(sql: String) -> Bool {

        /**

        1. 數據庫指針

        2. SQL 字符串的 C 語言格式

        3. 回調,執行完成 SQL 指令以後的函數回調,一般都是 nil

        4. 回調的第一個參數的指針

        5. 錯誤信息,一般也傳入 nil

        */

        return sqlite3_exec(db, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, nil, nil, nil) == SQLITE_OK

    }

    

    func insertTab() -> Bool {

        if self.openDatabase(){

            //這個 sql 語句特別之處在於 values 裏面有個? 號。在sqlite3_prepare函數裏,?號表示一個未定的值,它的值等下才插入。

            var sql = "inser () values(?,?,?)"

            sql = "update table set a=?,b=? where id =?"

            sql = "delete from tab where 1=1 "

            // 1. 準備語句

            var stmt: COpaquePointer = nil

            

            /**

            1. 數據庫句柄

            2. SQL C 語言的字符串

            3. SQL C 語言的字符串長度 strlen-1 會自動計算

            4. stmt 的指針

            5. 一般傳入 nil

            */

            var suc = sqlite3_prepare_v2(db, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, &stmt, nil)

            

            if suc == SQLITE_OK {

                

                

//                let intTran = UnsafeMutablePointer<Int>(bitPattern: -1)

//                let tranPointer = COpaquePointer(intTran)

//                let transient = CFunctionPointer<((UnsafeMutablePointer<()>) -> Void)>(tranPointer)

                

                //http://stackoverflow.com/questions/26883131/sqlite-transient-undefined-in-swift/26884081#26884081

                let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self)

                let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)

                

                //索引從1開始   這裏的數字123表明上面的第幾個問號,這裏將三個值綁定到三個綁定變量

                sqlite3_bind_int(stmt, 1, 123);

                sqlite3_bind_text(stmt, 2, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, SQLITE_TRANSIENT)

                sqlite3_bind_text(stmt, 3, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, SQLITE_TRANSIENT)

                

                //執行 語句

                suc = sqlite3_step(stmt)

                

                //釋放statement

                sqlite3_finalize(stmt)

                

                //關閉數據庫

                sqlite3_close(db)

                

                if suc == SQLITE_ERROR{

                    return false

                }else{

                    return true

                }

            }else{

                

                if let error = String.fromCString(sqlite3_errmsg(self.db)) {

                    let msg = "SQLiteDB - failed to prepare SQL: \(sql), Error: \(error)"

                    print(msg)

                }

                sqlite3_finalize(stmt)

                sqlite3_close(db)

                return false

            }

        }

        return false

        

    }

    

    ///  執行 SQL 返回一個結果集(對象數組)

    ///

    ///  :param: sql SQL 字符串

    func recordSet(sql: String) {

        // 1. 準備語句

        var stmt: COpaquePointer = nil

        /**

        1. 數據庫句柄

        2. SQL C 語言的字符串

        3. SQL C 語言的字符串長度 strlen-1 會自動計算

        4. stmt 的指針

        5. 一般傳入 nil

        */

        if sqlite3_prepare_v2(db, sql.cStringUsingEncoding(NSUTF8StringEncoding)!, -1, &stmt, nil) == SQLITE_OK {

            // 單步獲取SQL執行的結果 -> sqlite3_setup 對應一條記錄

            //查詢結果集中一條一條的遍歷全部的記錄,這裏的數字對應的是列值,注意這裏的列值,跟上面sqlite3_bind_text綁定的列值不同!必定要分開,否則會crash,只有這一處的列號不一樣,注意!

            while sqlite3_step(stmt) == SQLITE_ROW {

                // 獲取每一條記錄的數據

                recordData(stmt)

            }

        }

        sqlite3_finalize(stmt)

        sqlite3_close(db)

    }

    ///  獲取每一條數據的記錄

    ///

    ///  :param: stmt prepared_statement 對象

    func recordData(stmt: COpaquePointer) {

        // 獲取到記錄

        let count = sqlite3_column_count(stmt)

        print("獲取到記錄,共有多少列 \(count) ")

        // 遍歷每一列的數據

        for i in 0..<count {

            let type = sqlite3_column_type(stmt, i)

            // 根據字段的類型,提取對應列的值

            switch type {

            case SQLITE_INTEGER:

                print("整數 \(sqlite3_column_int64(stmt, i))")

            case SQLITE_FLOAT:

                print("小樹 \(sqlite3_column_double(stmt, i))")

            case SQLITE_NULL:

                print(" \(NSNull())")

            case SQLITE_TEXT:

                let chars = UnsafePointer<CChar>(sqlite3_column_text(stmt, i))

                let str = String(CString: chars, encoding: NSUTF8StringEncoding)!

                print("字符串 \(str)")

            case let type:

                print("不支持的類型 \(type)")

            }

        }

    }

}

相關文章
相關標籤/搜索