Swift 中使用 SQLite——查询数据

本文主要介绍如何查询 SQLite 结果集,以及封装 SQLite 的操作方法。

准备测试代码

/// 从数据库中加载 person 数组
class func persons() -> [Person]? {

    // 1. 准备 SQL
    let sql = "SELECT id, name, age, height FROM T_Person;"

    // 2. 访问数据库

    // 3. 返回结果
    return nil
}

在 SQLiteManager 中添加查询语句,准备结果集

/// 执行 SQL 返回查询结果集
///
/// - parameter sql: 任意给定的 SELETE 查询 SQL
func execRecordSet(sql: String) {

    // 1. 预编译 SQL
    /**
        参数

        1. 已经打开的数据库句柄
        2. 要执行的 SQL
        3. 以字节为单位的 SQL 最大长度,传入 -1 会自动计算
        4. SQL 语句句柄
            - 后续针对当前查询结果的操作全部基于此句柄
            - 需要调用 sqlite3_finalize 释放
        5. 未使用的指针地址,通常传入 nil
    */
    var stmt: COpaquePointer = nil
    if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
        print("SQL 错误")
        return
    }

    print("SQL 正确")
    // 2. 遍历集合

    // 3. 释放语句句柄 - 很重要,否则会内容泄漏
    sqlite3_finalize(stmt)
}

代码小结

  • 这一部分的工作可以看作是对字符串的 SQL 语句进行编译,并且检查是否存在语法问题
  • 编译成功后通过 sqlite3_step 执行 SQL,每执行一次,获取一条记录
  • 通过 while 循环直至执行完毕
  • 注意,指令执行完毕后需要释放

单步执行

// 2. 单步执行获取结果集内容
var row = 0
while sqlite3_step(stmt) == SQLITE_ROW {
    print("记录 \(row++)")
}

新建函数负责从 stmt 中获取一条完整的记录

/// 从 stmt 中获取一条完整的记录
///
/// - parameter stmt: stmt
private func record(stmt: COpaquePointer) {
    print("记录")
}

获取单条记录

所有函数都是以 sqlite3_column_ 开始

  • 获取列数
// 查询结果列数
let colCount = sqlite3_column_count(stmt)
print("列数 \(colCount)")
  • 遍历每一列获取对应的列名数据类型
// 遍历每一列
for col in 0..<colCount {
    // 列名
    let cName = sqlite3_column_name(stmt, col)
    let name = String(CString: cName, encoding: NSUTF8StringEncoding) ?? ""
    // 数据类型
    let type = sqlite3_column_type(stmt, col)

    print("列名 \(name)\(value)")
}

根据不同的数据类型转换对应的数值

  • 小数
var value: AnyObject?
switch type {
case SQLITE_FLOAT:
    value = sqlite3_column_double(stmt, col)
default:
    print("不支持的数据类型")
}

print("列名 \(name)\(value)")
  • 整数
case SQLITE_INTEGER:
    value = Int(sqlite3_column_int64(stmt, col))
  • 字符串
case SQLITE3_TEXT:
    let cText = UnsafePointer<Int8>(sqlite3_column_text(stmt, col))
    value = String(CString: cText, encoding: NSUTF8StringEncoding)
  • 空值
case SQLITE_NULL:
    value = NSNull()
  • 增加返回值和字典,调整后的代码如下:
/// 从 stmt 中获取当前记录的完整内容
///
/// - parameter stmt: stmt 句柄
private func record(stmt: COpaquePointer) -> [String: AnyObject] {

    // 1. 获取查询结果列数
    let colCount = sqlite3_column_count(stmt)

    // 单条记录字典
    var row = [String: AnyObject]()

    // 2. 遍历所有列,获取每一列的信息
    for col in 0..<colCount {
        // 1> 获取列名
        let cName = sqlite3_column_name(stmt, col)
        let name = String(CString: cName, encoding: NSUTF8StringEncoding) ?? ""

        // 2> 获取每列数据类型
        let type = sqlite3_column_type(stmt, col)

        // 3> 根据数据类型获取对应结果
        var value: AnyObject?
        switch(type) {
        case SQLITE_FLOAT:
            value = sqlite3_column_double(stmt, col)
        case SQLITE_INTEGER:
            value = Int(sqlite3_column_int64(stmt, col))
        case SQLITE3_TEXT:
            let cText = UnsafePointer<Int8>(sqlite3_column_text(stmt, col))
            value = String(CString: cText, encoding: NSUTF8StringEncoding)
        case SQLITE_NULL:
            value = NSNull()
        default:
            print("不支持的数据类型")
        }

//            print("列名 \(name) 值 \(value)")
        row[name] = value ?? NSNull()
    }

    return row
}

完善 execRecordSet 函数

  • 完善 execRecordSet 函数
/// 执行 SQL 返回查询结果集
///
/// - parameter sql: 任意给定的 SELETE 查询 SQL
func execRecordSet(sql: String) -> [[String: AnyObject]]? {

    // 1. 预编译 SQL
    /**
        参数

        1. 已经打开的数据库句柄
        2. 要执行的 SQL
        3. 以字节为单位的 SQL 最大长度,传入 -1 会自动计算
        4. SQL 语句句柄
            - 后续针对当前查询结果的操作全部基于此句柄
            - 需要调用 sqlite3_finalize 释放
        5. 未使用的指针地址,通常传入 nil
    */
    var stmt: COpaquePointer = nil
    if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
        print("SQL 错误")
        return nil
    }

    // 创建结果数组
    var rows = [[String: AnyObject]]()

    // 2. 遍历集合
    while sqlite3_step(stmt) == SQLITE_ROW {
        // 将单条记录字典添加到结果数组中
        rows.append(record(stmt))
    }

    // 3. 释放语句句柄 - 很重要,否则会内容泄漏
    sqlite3_finalize(stmt)

    // 4. 返回结果数组
    return rows
}
  • 在 Person 模型中加载 Person 列表
/// 从数据库中加载 person 数组
class func persons() -> [Person]? {

    // 1. 准备 SQL
    let sql = "SELECT id, name, age, height FROM T_Person;"

    // 2. 访问数据库获得字典数组
    guard let rows = SQLiteManager.sharedManager.execRecordSet(sql) else {
        return nil
    }

    // 3. 遍历字典数组 - 字典转模型
    var arrayM = [Person]()
    for row in rows {
        arrayM.append(Person(dict: row))
    }

    // 4. 返回结果集合
    return arrayM
}
  • 测试代码
print((Person.persons() ?? []) as NSArray)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值