swift sqlite 使用

导入 libsqlite3.0.tdb 

创建 Header.h 并配置到 Object-C Bridging Header 

在header.h中导入sqlite

#import "SQLite3.h"

然后就可以使用 sqlite 数据库了

 

//

//  ViewController.swift

//


import UIKit


class ViewController: UIViewController {


    

    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)")

            }

        }

    }

}

你可能感兴趣的:(sqlite)