数据表定义语句(DDL)
创建表:
create table if not exists <biaoming> (id integer primary key autoincrement,name text not NULL, age integer default 60)
删除表:
drop table if exists <biaoming>
更改表名:
alter table <biaoming> rename to <xinbiaoming>
给表增加列:
alter table <biaoming> add column <lieming> name text <zhibiaofu>
数据表操作语句(DML)
增加:
insert into <biaoming> (name, age,score) values {'xiaowang',90,80}
修改:
update <> set name = 'xiaohong',age = 20
update <> set score = 30 where id > 30
删除:
delete from <> where age is 18
DQL:查询语句
select name, age from <>
select * from <>
统计:
记录所有age不为空的个数(记录)select count(age) from <>
记录某个字段平均值 select avg(age) from <>
求和:sum zuida:max zuixiao:min
排序:
select *from <> order by score ASC(升序) 或者用 DESC(降序)
select *from <> order by score ASC,age DESC
分页:
select * from <> limit 1,3 1表示跳过1条,3表示跳过3条
多表查询:
OC中代码:
创建数据库
//参数1.数据库文件的路径 2.数据库对象,要打开的数据库
//返回值表示操作的状态码
int result = sqlite3_open(filename, &_db);
if (result == SQLITE_OK)
{
NSLog(@"数据库打开成功");
return YES;
}
else
{
NSLog(@"数据库打开失败");
//sqlite3_close 关闭数据库的方法
sqlite3_close(_db);
return NO;
}
创建表
char *error = nil;
//sqlite3_exec对数据库的操作:创建表,增删改,都建议用这个方法,查建议用其他的
//参数 1.数据库对象 2.sql语句 3.回调函数nil 4.回调函数的参数nil
if (sqlite3_exec(_db, [str UTF8String], nil, nil, &error)==SQLITE_OK)
{
NSLog(@"创建表成功");
}
else
{
NSLog(@"创建表失败:%s",error);
}
增删改查
//第一种方式sqlite3_exec
//sql为相关的增删改语句
sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK
//另一种方式,预处理语句sqlite3_prepare_v2
let prepareSql = "INSERT INTO \(tableName)(\(columnNames)) values (\(valuesStr))"
var stmt: COpaquePointer = nil
// 预处理SQL语句, 并生成 "语句句柄" , 后续会使用这样的语句句柄绑定数值, 并执行
if sqlite3_prepare_v2(db, prepareSql, -1, &stmt, nil) != SQLITE_OK
{
print("预处理失败")
// 释放语句资源
sqlite3_finalize(stmt)
return false
}
var index: Int32 = 1
for obj in values
{
if obj is Int
{
let temp: sqlite_int64 = obj as! sqlite_int64
sqlite3_bind_int64(stmt, index, temp)
} else if obj is Double
{
sqlite3_bind_double(stmt, index, obj as! Double)
}else if obj is String
{
/**
第5个参数
此参数有两个常数,SQLITE_STATIC告诉sqlite3_bind_text函数字符串为常量,可以放心使用;
而SQLITE_TRANSIENT会使得sqlite3_bind_text函数对字符串做一份拷贝。
一般使用这两个常量参数来调用sqlite3_bind_text。
*/
sqlite3_bind_text(stmt, index, obj as! String, -1, SQLITE_TRANSIENT)
}else {
continue
}
index++
}
var result: Bool = false
if sqlite3_step(stmt) == SQLITE_DONE
{
print("插入成功")
result = true
}else
{
print("插入失败")
result = false
}
// 将语句复位
if sqlite3_reset(stmt) != SQLITE_OK
{
print("复位失败")
result = false
}
// 释放语句
sqlite3_finalize(stmt)
return result
处理大数据耗时问题
插入10000条数据
sqlite_exec 10000 5.8080689907074
sqlite_prepare 10000 5.93309998512268
sqlite_prepare 分解后, 准备1次, 多次绑定/重置, 一次释放 5.11254101991653
分析结果
所以: 如果执行单条语句的话, 两者效率几乎一致
如果执行多条语句, 建议使用"准备语句"
两者区别:
sqlite_exec 函数是对"准备语句"的封装 (预处理语句->绑定参数->执行语句->重置语句->释放语句)
如果需要绑定二进制数据, 就必须要使用"准备语句了"
sqlite_exec 用法相对简单
整体耗时, 依然达到5秒左右, 非常庞大
原因: 因为sqlite3_exec, 或者 sqlite3_step 执行语句时, 都会自动开启事务-> 执行语句 -> 提交事务 这样的流程, 所以造成了, 多次开启和提交事务, 这个是非常耗时的操作
解决方案: 手动开启和提交事务即可, 这样 系统就不会自动开启事务和提交事务了
代码:
XMGSQLTool.shareInstance.beginTransaction()
for _ in 0...9999 {
stu.insertStudent()
}
XMGSQLTool.shareInstance.commitTransaction()
/** 开启事务 */
func beginTransaction() -> Bool
{
let sql = "BEGIN TRANSACTION"
return (sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK)
}
/** 提交事务 */
func commitTransaction() -> Bool
{
let sql = "COMMIT TRANSACTION"
return (sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK)
}
/** 回滚事务*/
func rollBackTransaction() -> Bool
{
let sql = "ROLLBACK TRANSACTION"
return (sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK)
}
开启事务BEGIN TRANSACTION
提交事务COMMIT TRANSACTION
回滚事务ROLLBACK TRANSACTION
查询的两种方式
let selectSql = "select * from t_student"
// 方式1:
// 参数1: 一个打开的数据库
// 参数2: 需要执行的SQL语句
// 参数3: 查询结果回调(执行0次或多次)
// 参数1: 参数4的值
// 参数2: 列的个数
// 参数3: 结果值的数组
// 参数4: 所有列的名称数组
// 返回值: 0代表继续执行一致到结束, 1代表执行一次
// 参数4: 回调函数的第一个值
// 参数5: 错误信息
sqlite3_exec(db, selectSql, { (parameter: UnsafeMutablePointer<Void>, columnCount: Int32, values: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>, columnNames: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>) -> Int32 in
let count = Int(columnCount)
for i: Int in 0..<count
{
let column = columnNames[i]
let columnStr = String(CString: column, encoding: NSUTF8StringEncoding)
let value = values[i]
let valueStr = String(CString: value, encoding: NSUTF8StringEncoding)
print(columnStr! + "= " + valueStr!)
}
return 0
}, nil, nil)
// 方式2:
// var stmt: COpaquePointer = nil
// if sqlite3_prepare(db, selectSql, -1, &stmt, nil) != SQLITE_OK
// {
// print("预处理失败")
// return
// }
//
// // 因为查询语句中没有占位?, 所以, 可以省略"绑定步骤"
// // 执行语句
// // sqlite3_step, 当使用这个方法时, 执行完毕后, 会自动跳到结果集的下一行, 如果依然有记录就返回SQLITE_ROW,
// while sqlite3_step(stmt) == SQLITE_ROW
// {
// let columnCount = sqlite3_column_count(stmt)
//
// for i in 0..<columnCount
// {
//
// // 获取列的类型
// let type = sqlite3_column_type(stmt, i)
//
// if type == SQLITE_TEXT
// {
// let text = UnsafePointer<Int8>(sqlite3_column_text(stmt, i))
// let str = String(CString: text, encoding: NSUTF8StringEncoding)
// print(str)
// }
//
// }
//
// }
//
// sqlite3_finalize(stmt)
FMDB使用:
优势:1.封装 2.提供了多线程访问数据方式
三个主要的类:
FMDatabase:是一个提供 SQLite 数据库的类,用于执行 SQL 语句。
FMResultSet:用在 FMDatabase 中执行查询的结果的类。
FMDatabaseQueue:在多线程下查询和更新数据库用到的类。
数据库创建
FMDatabase 是通过一个 SQLite 数据库文件路径创建的,此路径可以是以下三者之一:
一个文件的系统路径。磁盘中可以不存在此文件,因为如果不存在会自动为你创建。
一个空的字符串 @""。会在临时位置创建一个空的数据库,当 FMDatabase 连接关闭时,该数据库会被删除。
NULL。会在内存中创建一个数据库,当 FMDatabase 连接关闭时,该数据库会被销毁。
推荐文章:
[an example]http://www.jianshu.com/p/d60ee3c85d63