Funky、

Insist, Hard, Success

Welcome to Funky‘s zone. About me,so simple,Keep on coding,Keep on dancing. If you like something,stick to do!


OC/Swift-SQLite数据库

Demo地址
SQLite_OC&Swift_Demo地址

  • 其中 SQLite_Swift_Demo是Swift3.0语言写的SQLite基础
  • SQLiteTool_OC_Demo是使用OC语言,利用runtime对SQLite进行的封装,面向模型类操作数据库

1. 数据库简介

1.1 什么是数据库

  • 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库
  • 数据库可以分为2大种类
    • 关系型数据库(主流):(PC端 : Oracle/MySQL/SQL Server/Access/DB2/Sybase), (嵌入式/移动客户端 : SQLite)
    • 对象型数据库

1.2 iOS中数据存储的方式

  • Plist(NSArray\NSDictionary): 只能存储系统自带的数据类型, 比如NSDictory, NSArray等等. 自定义的对象无法存储
  • Preference(偏好设置\NSUserDefaults): 本质就是一个plist文件; 也是只能存储系统自带的数据类型, 自定义的对象无法存储
  • NSCoding(NSKeyedArchiver\NSkeyedUnarchiver): 可以存储自己定义的数据类型, 但是都是一次性的全数据操作
  • SQLite3 : 存储一些大批量的数据, 排序, 统计等操作
  • Core Data : 对SQLite3的一层面向对象的包装, 本质还是要转换成为对应的SQL语句去执行
  • 钥匙串 : APP之间数据共享/系统级别的加密, 安全性高/当APP 被删除时, 存储的数据依然存在

1.3 什么是SQLite

  • SQLite是一款轻型的嵌入式数据库, 它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了,它的处理速度比Mysql、PostgreSQL这两款著名的数据库都还快

1.4 如何存储数据到数据库

  • 数据库的存储结构和excel很像,以表(table)为单位
  • 数据库存储数据的步骤 : 新建数据库文件 –> 新建一张表(table)–> 添加多个字段(column,列,属性)–> 添加多行记录(row,每行存放多个字段对应的值)

2. SQL语言简介

2.1 什么是SQL?

  • SQL(structured query language):结构化查询语言
  • SQL是一种对关系型数据库中的数据进行定义和操作的语言
  • SQL语言简洁,语法简单,好学好用

2.2 什么是SQL语句

  • 使用SQL语言编写出来的句子\代码,就是SQL语句, 在程序运行过程中,要想操作(增删改查,CRUD)数据库中的数据,必须使用SQL语句, Create , Retrive, Update, Delete

2.3 SQL语句的特点

  • 不区分大小写(比如数据库认为user和UsEr是一样的)
  • 每条语句都必须以分号 ; 结尾

2.4 SQL中的常用关键字

  • 数据库中不可以使用关键字来命名表、字段
  • select、insert、update、delete、from、create、where、desc、order、by、group、table、alter、view、index等等

2.5 SQL语句的种类

  • 数据定义语句(DDL:Data Definition Language): 包括create和drop, Alert等操作, 在数据库中创建新表或删除表(create table或 drop table)
  • 数据操作语句(DML:Data Manipulation Language): 包括insert、delete、update等操作
  • 数据查询语句(DQL:Data Query Language): 可以用于查询获得表中的数据, 关键字select是DQL(也是所有SQL)用得最多的操作, 其他DQL常用的关键字有where,order by,group by和having

3. DDL语句

3.1 创表

  • 格式:create table 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;
  • 示例:create table t_student (id integer, name text, age inetger, score real) ;
  • 创建表格时, 最好加个表格是否已经存在的判断, 这个防止语句多次执行时发生错误,create table if not exists 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;
  • 注意:实际上SQLite是无类型的,就算声明为integer类型,还是能存储字符串文本(主键除外),建表时声明啥类型或者不声明类型都可以,也就意味着创表语句可以这么写:create table t_student(name, age); 为了保持良好的编程规范、方便程序员之间的交流,编写建表语句的时候最好加上每个字段的具体类型

3.2 删表

  • 格式:drop table if exists 表名 ;
  • 示例:drop table t_student ;

3.3 修改表

  • 修改表名:ALTER TABLE 旧表名 RENAME TO 新表名
  • 新增属性:ALTER TABLE 表名 ADD COLUMN 列名 数据类型 限定符
  • 注意: sqlite里面只能实现Alter Table的部分功能,不能删除一列, 修改一个已经存在的列名

4. 约束

4.1 简单约束

  • 不能为空 not null :规定字段的值不能为null
  • 不能重复 unique :规定字段的值必须唯一
  • 默认值 default :指定字段的默认值
  • 示例:create table t_student (id integer, name text not null unique, age integer not null default 1) ;
    表示,name字段不能为null,并且唯一,age字段不能为null,并且默认为1

4.2 主键约束

  • 什么是主键

    • 主键(Primary Key,简称PK)用来唯一地标识某一条记录,例如t_student可以增加一个id字段作为主键,相当于人的身份证
    • 主键可以是一个字段或多个字段
  • 添加主键约束的原因

    • 如果t_student表中就name和age两个字段,而且有些记录的name和age字段的值都一样时,那么就没法区分这些数据,造成数据库的记录不唯一,这样就不方便管理数据
    • 良好的数据库编程规范应该要保证每条记录的唯一性,为此,增加了主键约束,也就是说,每张表都必须有一个主键,用来标识记录的唯一性
  • 主键的设计原则

    • 主键应当是对用户没有意义的
    • 永远也不要更新主键
    • 主键不应包含动态变化的数据
    • 主键应当由计算机自动生成
  • 主键的声明

    • 在创表的时候用primary key声明一个主键:create table t_student (id integer primary key, name text, age integer) ; integer类型的id作为t_student表的主键
    • 主键字段:只要声明为primary key,就说明是一个主键字段,主键字段默认就包含了not null 和 unique 两个约束
    • 如果想要让主键自动增长(必须是integer类型),应该增加autoincrement,例如:create table t_student (id integer primary key autoincrement, name text, age integer) ;

5. DML语句

5.1 插入数据(insert)

  • 格式:insert into 表名 (字段1, 字段2, …) values (字段1的值, 字段2的值, …) ;
  • 示例:insert into t_student (name, age) values (‘funky’, 18) ;
  • 注意: 数据库中的字符串内容应该用单引号 ’ 括住

5.2 更新数据(update)

  • 格式:update 表名 set 字段1 = 字段1的值, 字段2 = 字段2的值, … ;
  • 示例:update t_student set name = ‘funky’, age = 20 ;
  • 注意: 上面的示例会将t_student表中所有记录的name都改为funky,age都改为20

5.3 删除数据(delete)

  • 格式:delete from 表名 ;
  • 示例:delete from t_student ;
  • 注意: 上面的示例会将t_student表中所有记录都删掉

6. 条件语句

6.1 作用

  • 如果只想更新或者删除某些固定的记录,那就必须在DML语句后加上一些条件

6.2 条件语句的常见格式

  • where 字段 = 某个值 ; // 不能用两个 =
  • where 字段 is 某个值 ; // is 相当于 =
  • where 字段 != 某个值 ;
  • where 字段 is not 某个值 ; // is not 相当于 !=
  • where 字段 > 某个值 ;
  • where 字段1 = 某个值 and 字段2 > 某个值 ; // and相当于C语言中的 &&
  • where 字段1 = 某个值 or 字段2 = 某个值 ; // or 相当于C语言中的 ||

6.3 示例

  • 将t_student表中年龄大于10 并且 姓名不等于wex的记录,年龄都改为 5
    • update t_student set age = 5 where age > 10 and name != ‘wex’ ;
  • 删除t_student表中年龄小于等于10 或者 年龄大于30的记录
    • delete from t_student where age <= 10 or age > 30 ;
  • update t_student set score = age where name = ‘wex’ ;
    • 将t_student表中名字等于wex的记录,score字段的值 都改为 age字段的值

7. DQL查询语句

7.1 格式

  • select 字段1, 字段2, … from 表名 ;
  • select * from 表名; // 查询所有的字段
  • 示例:
    • select name, age from t_student ;
    • select * from t_student ;
    • select * from t_student where age > 10 ; // 条件查询

7.2 统计

  • count(X):select count(*) from t_student 计算所有记录个数,select count(age) from t_student 计算age有值的记录个数(Null不计算在内)
  • avg(X):计算某个字段的平均值(如果是NULL,就不包含在内)
  • sum(X):计算某个字段的总和
  • max(X):计算某个字段的最大值
  • min(X):计算某个字段的最小值

7.3 排序

  • 查询出来的结果可以用order by进行排序
    • select 字段1, 字段2 from 表名 order by 字段 ;
    • select * from t_student order by age ;
  • 默认是按照升序排序(由小到大),也可以变为降序(由大到小)
    • select * from t_student order by age desc ; //降序
    • select * from t_student order by age asc ; // 升序(默认)
  • 也可以用多个字段进行排序
    • select * from t_student order by age asc, height desc ;
    • 先按照年龄排序(升序),年龄相等就按照身高排序(降序)

7.4 limit分页

  • 使用limit可以精确地控制查询结果的数量,比如每次只查询10条数据
  • 格式:select * from 表名 limit 数值1, 数值2 ;
  • 示例:select * from t_student limit 4, 8 ;(跳过最前面4条语句,然后取8条记录)
  • 分页
    • limit常用来做分页查询,比如每页固定显示5条数据,那么应该这样取数据,第1页:limit 0, 5 第2页:limit 5, 5 第3页:limit 10, 5 第n页:limit 5*(n-1), 5
    • 特殊案例:select from t_student limit 7 ;相当于select from t_student limit 0, 7 ;(表示取最前面的7条记录)

7.5 多表查询

  • 多表查询:select 字段1, 字段2, … from 表名1, 表名2 ;
  • 别名:select 别名1.字段1 as 字段别名1, 别名2.字段2 as 字段别名2, from 表名1 as 别名1, 表名2 as 别名2 ;
  • 可以给表或者字段单独起别名,as 可以省略
  • 表连接查询:select 字段1, 字段2, … from 表名1, 表名2 where 表名1.id = 表名2.id;
  • 外键:如果表A的主关键字是表B中的字段,则该字段称为表B的外键,保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值或使用空值。

8. Swift代码实现DDL/DML/DQL

8.1 DDL语句

ViewController.swift

// ----- DDL语句 -----

// 创建表
SQLiteTool.shareInstance.createTable()

// 删除表
SQLiteTool.shareInstance.dropTable()

SQLiteTool.swift

class SQLiteTool: NSObject {

    static let shareInstance = SQLiteTool()

    var db: OpaquePointer? = nil

    override init() {
        super.init()

        // 1. 创建一个数据库
        /*
        sqlite3_open:打开一个指定的数据库, 如果数据库不存在就创建,如果存在就直接打开,并且赋值给参数2
        参数1: 数据库路径
        参数2: 一个已经打开的数据库(如果后期要执行sql语句, 都需要借助这个对象)
        关于sqlite 数据库文件的后缀名, 没有要求, 一般常用 sqlite db db3作后缀名
        */

        let path = "/Users/Funky/Desktop/sqlite_demo.sqlite"

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

            print("执行成功")
            createTable()

        }else {
            print("执行失败")
        }

    }


    // 创建表
    func createTable() -> () {
        let sql = "create table if not exists t_stu(id integer primary key autoincrement, name text not null, age integer, score real default 60)"
        let result = execute(sql)
        if result {
            print("创建表成功")
        }
    }


    // 删除表
    func dropTable() -> () {
        let sql = "drop table if exists t_stu"
        let result = execute(sql)
        if result {
            print("删除表成功")
        }
    }


    func execute(_ sql: String) -> Bool {
        // 参数1: 已经打开的数据库
        // 参数2: 需要执行的sql字符串
        // 参数3: 执行回调
        // 参数4: 参数3 参数1
        // 参数5: 错误信息
        return (sqlite3_exec(db, sql, nil , nil, nil) == SQLITE_OK)
    }

}

8.2 DML语句

ViewController.swift

// ----- DML语句 -----

let stu1 = Student(name: "funky", age: 18, score: 100)

// 插入数据
stu1.insertStudent()

// 删除 name 为funky的数据
Student.deleteStu(name: "funky")

// 修改数据
let stu2 = Student(name: "Bob", age: 28, score: 10)
stu1.updateStudent(newStu: stu2)

// 绑定插入数据
stu1.bindInsert()

// 绑定插入大批量数据优化(手动开启‘事物’)
stu1.fastBindInsert()


/*

--> 事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,可以将逻辑相关的一组操作绑定在一起,保持数据的完整性。

--> 事务通常是以BEGIN TRANSACTION开始,以COMMIT TRANSACTION或ROLLBACK TRANSACTION结束。
COMMIT表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。
ROLLBACK表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有以完成的操作全部撤消,滚回到事务开始的状态。

*/

SQLiteTool.shareInstance.beginTransaction()

// 张三-10
let result1 = Student.update(sql: "update t_stu set money = money - 10 where name = 'zhangsan'")

// 李四 + 10
let result2 = Student.update(sql: "update t_stu set money = money + 10 where name = 'lisi'")

if result1 && result2 {
    SQLiteTool.shareInstance.commitTransaction()
}else {
    SQLiteTool.shareInstance.rollbackTransaction()
}

Student.swift

class Student: NSObject {

    var name: String = ""
    var age: Int = 0
    var score: Float = 0.0

    init(name: String, age: Int, score: Float) {
        super.init()
        self.name = name
        self.age = age
        self.score = score
    }

    // 1. 插入数据
    func insertStudent() -> () {

        let sql = "insert into t_stu(name, age, score) values ('\(name)', \(age), \(score))"

        if  SQLiteTool.shareInstance.execute(sql)  {
            print("插入成功")
        }
    }


    // 2. 删除 name 为xxx的数据
    class func deleteStu(name: String) -> () {
        let sql = "delete from t_stu where name = '\(name)'"

        if  SQLiteTool.shareInstance.execute(sql)  {
            print("删除成功")
        }
    }


    // 3. 修改数据内容
    func updateStudent(newStu: Student) -> () {

        let sql = "update t_stu set name = '\(newStu.name)', age = \(newStu.age), score = \(newStu.score) where name = '\(name)'"

        print(sql)

        if  SQLiteTool.shareInstance.execute(sql)  {
            print("修改成功")
        }else {
            print("修改失败")
        }

    }


// 4. 绑定插入数据
func bindInsert() -> () {

    // 根据sql字符串, 创建准备语句
    // 参数1: 一个已经打开的数据库
    // 参数2: sql 字符串 "123234324"
    // 参数3: 取出字符串的长度 "2"  -1 : 代表自动计算
    // 参数4: 预处理语句
    // 参数5: 根据参数3的长度, 取出参数2的值以后, 剩余的参数
    //sqlite3_prepare_v2(db: OpaquePointer!, zSql: UnsafePointer<Int8>!, nByte: Int32, ppStmt: UnsafeMutablePointer<OpaquePointer?>!, pzTail: UnsafeMutablePointer<UnsafePointer<Int8>?>!)

    let sql = "insert into t_stu(name, age, score) values (?, ?, ?)"
    let db = SQLiteTool.shareInstance.db
    var stmt: OpaquePointer? = nil
    if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
        print("预处理失败")
        return
    }


    // 2. 绑定参数
    // 参数1: 准备语句
    // 参数2: 绑定值的索引 索引从1
    // 惨数3: 需要绑定的值
    sqlite3_bind_int(stmt, 2, 20)
    sqlite3_bind_double(stmt, 3, 59.9)

    // 绑定文本(姓名)
    // 参数1: 准备语句
    // 参数2: 绑定的索引 1
    // 参数3: 绑定的值 "123"
    // 参数4: 值取出多少长度 -1 , 取出所有
    // 参数5: 值的处理方式
    // SQLITE_STATIC : 人为参数是一个常量, 不会被释放, 处理方案: 不做任何的引用
    // SQLITE_TRANSIENT: 会对参数, 进行一个引用

    let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
    sqlite3_bind_text(stmt, 1, "zhangsan2", -1, SQLITE_TRANSIENT)

    // 3. 执行sql语句, 准备语句
    if sqlite3_step(stmt) == SQLITE_DONE {
        print("执行成功")
    }

    // 4. 重置语句
    sqlite3_reset(stmt)

    // 5. 释放准备语句
    sqlite3_finalize(stmt)

}


// 问题: 如果使用 sqlite3_exec 或者, sqlite3_step()来执行sql语句, 会自动开启一个"事务", 然后, 自动提交"事务"
// 方案: 只需要手动开启事务, 手动提交事务, 这时候, 函数内部, 就不会自动开启 和提交事务


// 5. 优化绑定插入数据(插入大批量数据)
func fastBindInsert() -> () {

    let sql = "insert into t_stu(name, age, score) values (?, ?, ?)"
    let db = SQLiteTool.shareInstance.db
    var stmt: OpaquePointer? = nil
    if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
        print("预处理失败")
        return
    }

    // 手动开启事务
    SQLiteTool.shareInstance.beginTransaction()

    for i in 0..<100000 {

        let value = Int32(i)
        sqlite3_bind_int(stmt, 2, value)
        sqlite3_bind_double(stmt, 3, 59.9)

        let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
        sqlite3_bind_text(stmt, 1, "zhangsan2", -1, SQLITE_TRANSIENT)

        if sqlite3_step(stmt) == SQLITE_DONE {
            // print("执行成功")
        }

        sqlite3_reset(stmt)

    }

    // 提交事务
    SQLiteTool.shareInstance.commitTransaction()

    sqlite3_finalize(stmt)


}


class func update(sql: String) -> Bool {
    return SQLiteTool.shareInstance.execute(sql)
}

}

SQLiteTool.swift

class SQLiteTool: NSObject {

    func execute(_ sql: String) -> Bool {
        return (sqlite3_exec(db, sql, nil , nil, nil) == SQLITE_OK)

    }


    // 问题: 如果使用 sqlite3_exec 或者, sqlite3_step()来执行sql语句, 会自动开启一个"事务", 然后, 自动提交"事务"
    // 方案: 只需要手动开启事务, 手动提交事务, 这时候, 函数内部, 就不会自动开启 和提交事务


    // 开启事务
    func beginTransaction() -> () {
        let sql = "begin transaction"
    if execute(sql) {
        print("开启事务成功")
        }
    }

    // 提交事务
    func commitTransaction() -> () {
        let sql = "commit transaction"
        if execute(sql) {
            print("提交事务成功")
        }
    }



    // 事物回滚
    func rollbackTransaction() -> () {
        let sql = "rollback transaction"
        if execute(sql){
            print("事物回滚成功")
        }
    }

}

8.3 DQL语句

ViewController.swift

// ----- DQL语句 -----

// 查询所有,方案1
// 作用: 可以通过回调来获取结果, 步骤相对来说简单, 结果数据类型没有特定类型(id),统一是字符串
Student.queryAll()

// 查询所有,方案2
// 作用: 可以处理不同特定类型, 步骤相对来说复杂
Student.queryAllOther()

Student.swift

// 6. 查询所有,方案1
class func queryAll() -> () {

    let sql = "select * from t_stu"
    let db = SQLiteTool.shareInstance.db

    // 参数1: 一个打开的数据库
    // 参数2: sql语句
    // 参数3: 回调代码块
    // 参数1 传递过来的值
    // 参数2 列的个数
    // 参数3 值的数组
    // 参数4: 列名称的数组
    // 返回值: 0, 继续查询 1: 终止查询
    // 参数4: 传递到参数3里面的第一个参数
    // 参数5: 错误信息
    // char *
    let result = sqlite3_exec(db, sql, { (
        firstValue, columnCount, values , columnNames ) -> Int32 in

        let count = Int(columnCount)
        for i in 0..<count {
            // 列的名称
            let columnName = columnNames?[i]
            let columnNameStr = String(cString: columnName!, encoding: String.Encoding.utf8)
            // 值
            let value = values?[i]
            let valueStr = String(cString: value!, encoding: String.Encoding.utf8)

            print(columnNameStr ?? "", valueStr ?? "")
        }
        return 0

    }, nil, nil)

    // print(result)
    if result == SQLITE_ABORT {
        print("查询成功")
    }else {
        print("查询失败")
    }


}

// 7. 查询所有,方案2
class func queryAllOther() {

    // 准备语句 历程
    let sql = "select * from t_stu;"
    // 1. 创建 "准备语句"
    // 参数1: 打开的数据库
    // 参数2: sql字符串
    // 参数3: 字符串, 取的长度 -1代表, 去所有的
    // 参数4: 准备语句的指针
    // 参数5: 剩余的sql字符串
    let db = SQLiteTool.shareInstance.db
    var stmt: OpaquePointer? = nil
    if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
        print("预处理失败")
        return
    }

    // 2. 绑定参数(这一步可以省略)

    // 3. 执行"准备语句"
    // sqlite3_step . 作用, 执行DQL, 语句时, 会把, 执行得到的结果, 放到"准备语句"stmt里面

    while sqlite3_step(stmt) == SQLITE_ROW {

        // 读取结果
        // 从准备语句里面进行读取
        // 1. 计算预处理语句里面得到的结果是多少列
        let count = sqlite3_column_count(stmt)
        for i in 0..<count {

            // 2. 取出列的名称
            let columnName = sqlite3_column_name(stmt, i)
            let columnNameStr = String(cString: columnName!, encoding: String.Encoding.utf8)

            print(columnNameStr ?? "")
            // 3. 取出列的值
            // 不同的数字类型, 是通过不同的函数进行获取
            // 3.1 获取这一列的类型
            let type = sqlite3_column_type(stmt, i)
            // 3.2. 根据不同的类型, 使用不同的函数, 获取结果
            if type == SQLITE_INTEGER {
                let value = sqlite3_column_int(stmt, i)
                print(value)
            }
            if type == SQLITE_FLOAT {
                let value = sqlite3_column_double(stmt, i)
                print(value)
            }
            if type == SQLITE_TEXT {

                let valueStr = String(cString: sqlite3_column_text(stmt, i))
                    print(valueStr)
                }

            }


        }

        // 4. 重置"准备语句"(这一步可以省略)

        // 5. 释放"准备语句"
        sqlite3_finalize(stmt)

}

9.SQLite函数总结

1.打开数据库
int sqlite3_open(
    const char *filename,   // 数据库的文件路径
    sqlite3 **ppDb          // 数据库实例
);

2.执行任何SQL语句
int sqlite3_exec(
    sqlite3*,                                  // 一个打开的数据库实例
    const char *sql,                           // 需要执行的SQL语句
    int (*callback)(void*,int,char**,char**),  // SQL语句执行完毕后的回调
    void *,                                    // 回调函数的第1个参数
    char **errmsg                              // 错误信息
);

3.检查SQL语句的合法性(查询前的准备)
int sqlite3_prepare_v2(
    sqlite3 *db,            // 数据库实例
    const char *zSql,       // 需要检查的SQL语句
    int nByte,              // SQL语句的最大字节长度
    sqlite3_stmt **ppStmt,  // sqlite3_stmt实例,用来获得数据库数据
    const char **pzTail
);

4.查询一行数据
int sqlite3_step(sqlite3_stmt*); // 如果查询到一行数据,就会返回SQLITE_ROW

5.利用stmt获得某一字段的值(字段的下标从0开始)
double sqlite3_column_double(sqlite3_stmt*, int iCol);  // 浮点数据
int sqlite3_column_int(sqlite3_stmt*, int iCol); // 整型数据
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); // 长整型数据
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); // 二进制文本数据
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);  // 字符串数据

10.SQLite语句总结

/*简单约束*/
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER NOT NULL);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER DEFAULT 1);

/*分页*/
SELECT * FROM t_student ORDER BY id ASC LIMIT 30, 10;

/*排序*/
SELECT * FROM t_student WHERE score > 50 ORDER BY age DESC;
SELECT * FROM t_student WHERE score < 50 ORDER BY age ASC , score DESC;

/*计量*/
SELECT COUNT(*) FROM t_student WHERE age > 50;

/*别名*/
SELECT name as myName, age as myAge, score as myScore FROM t_student;
SELECT name myName, age myAge, score myScore FROM t_student;
SELECT s.name myName, s.age myAge, s.score myScore FROM t_student s WHERE s.age > 50;

/*查询*/
SELECT name, age, score FROM t_student;
SELECT * FROM t_student;

/*修改指定数据*/
UPDATE t_student SET name = 'MM' WHERE age = 10;
UPDATE t_student SET name = 'WW' WHERE age is 7;
UPDATE t_student SET name = 'XXOO' WHERE age < 20;
UPDATE t_student SET name = 'NNMM' WHERE age < 50 and score > 10;

/*删除数据*/
DELETE FROM t_student;

/*更新数据*/
UPDATE t_student SET name = 'ZhangSan';
update stu_tmp set name = (select name from stu where stu_tmp.stuNum = stu.stuNum)

/*插入数据*/
INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'jonathan');
INSERT INTO t_student(name, age) VALUES ('zs', '28');
INSERT INTO t_student(score) VALUES (100);

/*插入数据*/
INSERT INTO t_student(name, age, score) VALUES ('zs', '28', 100);

/*添加主键*/
CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, score REAL);
/*添加主键*/
CREATE TABLE IF NOT EXISTS t_student (id INTEGER, name TEXT, age INTEGER, score REAL, PRIMARY KEY(id));

/*删除表*/
DROP TABLE IF EXISTS t_student;

/*创建表*/
CREATE TABLE IF NOT EXISTS t_student(id INTEGER , name TEXT, age , score REAL);

最近的文章

OC-导航控制器相关

[TOC] 1. 整体概念 解释: UINavigationController是容器类的视图控制器,是UIViewController的子类,它以栈的形式管理一组视图控制器ViewController,位于栈底的视图是导航控制器的根视图rootViewController 每一个导航控制器都包含 …

于  knowledge 继续阅读
更早的文章

OC-触摸事件&响应者链条

iOS中的事件 在用户使用app过程中,会产生各种各样的事件,iOS中的事件可以分为3大类型:触摸事件,加速计事件,远程控制事件 响应者对象 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为响应者对象 UIApplication、UIView …

于  knowledge 继续阅读
comments powered by Disqus