H:/1124/00_SQLite笔记.txt
1. 数据库中的指令不区分大小写; 2. 数据库命名时,不能与关键字冲突 * 在命名数据表时,一般使用“t_”作为前缀 在sqlite中是不区分字段类型的,不过为了保持编程规范,在创建数据表时,最好指定数据类型 3. SQL语言中,作为程序员一定要会SELECT,其他的命令,通常可以借助工具来帮助编写 4. SQL语句都是以;作为结尾的 5. 在数据库中,数据表的名字不能够重复! *** 数据库操作步骤 1. 创建数据表 2. 插入数据 完成第二步之后,基本先告一段落 后续就是对现有数据库中的内容进行操作 1) 新增记录 insert 2) 修改记录 update 3) 删除记录 delete 4) 查询记录 select *** 数据库相对plist的好处 ** 分页查询指令 # limit 指令用于限制查询出来的结果数量 # 第一个数值表示从哪条记录开始(起始是0) # 第二个数值表示一次取多少条记录,如果要分页显示,通常第二个数值固定不变,表示每页需要显示的记录条数 # 第一页 select * from t_person limit 0, 3; # 第二页 select * from t_person limit 3, 3; # 第三页 select * from t_person limit 6, 3; ** 查询排序 * ASC 升序(默认的排序方法) * DESC 降序 * 由左至右排序的优先级依次降低,也就是第一个排序列的优先级是最高的 SELECT * FROM t_person ORDER BY age ASC, id DESC; ** 能够定向地查到具体需要的内容 # 从数据库查出名字叫做史湘云的记录 select * from t_person where name = '史湘云'; # 从数据库查出名字以wang开头的记录 select * from t_person where name like '史湘云%'; # 从数据库查出名字中包含a的记录,通常用于模糊查询,建议不要搞太多字段组合模糊查询,那样性能会非常差! select * from t_person where name like '%a%'; ** 可以对数据进行统计 # 取出所有数据的总数目 select count(*) from t_person; # 统计符合条件的记录条数 select count(*) from t_person where name like 'wang%'; # 选择指定列的最大值 select max(age) from t_person; # 选择指定列的最小值 select min(age) from t_person; # 计算指定列的平均值 select avg(age) from t_person; # 计算指定列数值的总数 select sum(age) from t_person; ** 更新指令 # 更新一个字段 update t_person set name = '妙玉' where name = '史湘云'; # 更新多个字段,每个字段之间使用,分隔 update t_person set age = 20, height = 2.0 where name = '妙玉'; # 需要注意的是:使用更新指令时,最好能够准确地知道唯一的一条要更新的记录, 否则其他所有满足条件的记录都会被修改。 ** 自动增长是由服务器来控制的 *** 关系 为什么要有关系 1. 数据“冗余”,所谓数据容易,就是存储了多余的数据 2. 在数据库中的关系有: * 一对一 * 一对多 * 多对一 通常,一对多和多对一关系存储在时,就需要使用多个表表示。 关于left jion和jion的选择 ** left join 1)如果要查询左边表中的所有符合条件的数据,使用left jion 2) 通常查询出来的结果会多,因为右边表不存在的记录,同样可能会被查询出来, 查询出来之后,右边表不存在的记录,全部为NULL ** join 1)如果要两个表中同时存在的符合条件的数据,使用jion 2) 通常查询出来的结果会比左连接少,因为右边表不存在的记录,不会显示出来 通常在使用时,左边的表是主要信息表,右边的表是辅助修饰的信息表,其内容可有可无, 因此,在实际应用中,left jion使用的比较频繁!如果用join的话,有可能会“丢(有些存在的数据不显示)”数据 在使用连接查询多个表时,如果有重名的字段,可以使用as的方法,给字段起一个别名,示例代码如下: select s.name, s.age, s.phone, b.name as bookname, b.price from t_student s join t_book b on b.id = s.book_id
// // Book.h // 数据库关系 // // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. // #import <Foundation/Foundation.h> @interface Book : NSObject // book主键 @property (assign, nonatomic) NSInteger ID; // book书名 @property (copy, nonatomic) NSString *name; // book价格 @property (assign, nonatomic) float price; @end
// // Book.m // 数据库关系 // // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. // #import "Book.h" @implementation Book @end
// // Student.h // 数据库关系 // // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. // #import <Foundation/Foundation.h> #import "Book.h" @interface Student : NSObject // student主键 @property (assign, nonatomic) NSInteger ID; // student姓名 @property (copy, nonatomic) NSString *name; // student电话 @property (copy, nonatomic) NSString *phone; // student年龄 @property (assign, nonatomic) NSInteger age; // student拥有的书 @property (strong, nonatomic) Book *book; @end
// // Student.m // 数据库关系 // // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. // #import "Student.h" @implementation Student @end
// PersonManager.h // 02.SQLite基本使用 // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. #import <Foundation/Foundation.h> // ~~~~~~~~~~使用Singleton.h宏定义单例,步骤1:~~~~~~~~~~~~~~ #import "Singleton.h" #import "Person.h" @interface PersonManager : NSObject // ~~~~~~~~~~使用Singleton.h宏定义单例,步骤2:~~~~~~~~~~~~~~ single_interface(PersonManager) // 新增个人记录 - (void)addPerson:(Person *)person; // 修改个人记录(修改传入Person对象ID对应的数据库记录的内容) - (void)updatePerson:(Person *)person; // 删除个人记录 - (void)removePerson:(NSInteger)personID; // 查询所有用户信息列表 - (NSArray *)allPersons; /** * 模糊查询所有姓名中包含name字符串的用户记录 * @param name 姓名部分字符串 * @return 查询结果集 */ - (NSArray *)personsWithName:(NSString *)name; @end
// PersonManager.m // 02.SQLite基本使用 // Created by apple on 13-11-24. #import "PersonManager.h" // 导入sqlite3头文件 #import <sqlite3.h> /* 本文件相当于Java中DAO层,PersonDao,又结合了service层 sqlite3使用方法: 1,SQLite3常用的5种数据类型:text、integer、float、boolean、blob 在iOS中要使用SQLite3,需要添加库文件: libsqlite3.dylib并导入主头文件,这是一个C语言的库 2,创建数据库(sqlite3_opendb) 单步执行操作(sqlite3_exec) 创建数据表 数据操作 插入数据 更新数据 删除数据 查询操作 sqlite3_prepare_v2检查sql的合法性 sqlite3_step逐行获取查询结果 sqlite3_coloum_xxx获取对应类型的内容 sqlite3_finalize释放stmt */ @interface PersonManager() { // SQLite数据库的连接,基于该连接可以进行数据库操作 sqlite3 *_db; } @end @implementation PersonManager // ~~~~~~~~~~使用Singleton.h宏定义单例,步骤3:~~~~~~~~~~~~~~ // 通过宏,创建单例 PersonManager single_implementation(PersonManager) // 在初始化方法中完成数据库连接工作 - (id)init { self = [super init]; if (self) { // 1. 调用自定义方法,创建/打开/(连接)数据库 [self openDB]; // 2. 调用自定义方法,创建数据表 [self createTable]; } return self; } #pragma mark - 自定义,数据库操作方法1,创建/打开数据库 - (void)openDB { // 先找到documents目录,然后生成存放在沙盒中的数据库完整路径 NSString *docDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *dbName = [docDir stringByAppendingPathComponent:@"my.db"]; // 如果数据库不存在,怎新建并打开一个数据库,否则直接打开 // sqlite3_open方法的参数1:c字符串,参数2,sqlite3 对象的地址 if (SQLITE_OK == sqlite3_open(dbName.UTF8String, &_db)) { NSLog(@"创建/打开数据库成功。"); } else { NSLog(@"创建/打开数据库失败。"); } } #pragma mark - 自定义,数据库操作方法2,创建table数据表(必须加上IF NOT EXISTS) - (void)createTable { NSString *sql = @"CREATE TABLE IF NOT EXISTS t_person (id integer PRIMARY KEY AUTOINCREMENT, name text,age integer,phoneNo text)"; // 调用自定义方法,执行sql语句 [self execSql:sql msg:@"创建数据表"]; } /** 自定义,数据库操作方法3,执行sql语句 * @param sql sql语句 * @param msg 提示信息 */ - (void)execSql:(NSString *)sql msg:(NSString *)msg { char *errmsg; // 所谓回调:sqlite3_exec执行完成sql之后调用的方法,叫做回调方法 // sqlite3_exec()方法:参数1,sqlite3连接(句柄) // 参数2,c类型的sql文本, // 参数3,callback 回调block代码块 // 参数4,参数3中的回调中的第1个参数 // 参数5,存放错误信息,指向字符的指针的地址 if (SQLITE_OK == sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errmsg)) { NSLog(@"%@的sql语句执行成功", msg); } else { NSLog(@"%@的sql语句执行失败 - %s", msg, errmsg); } } #pragma mark - 成员方法,增加一条个人记录 - (void)addPerson:(Person *)person { NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_person (name, age, phoneNo) VALUES ('%@', %d, '%@')", person.name, person.age, person.phoneNo]; [self execSql:sql msg:@"添加个人记录"]; } #pragma mark - 成员方法,更新一个person对象信息 - (void)updatePerson:(Person *)person { } #pragma mark - 成员方法,根据ID删除一条个人记录 - (void)removePerson:(NSInteger)personID { } #pragma mark - 成员方法,查询所有的个人记录(返回对象数组) - (NSArray *)allPersons { NSString *sql = @"SELECT id, name, age, phoneNo FROM t_person"; // 调用自定义方法queryPersonsWithSql return [self queryPersonsWithSql:sql]; } #pragma mark - 成员方法,根据姓名模糊查询个人记录(返回对象数组) - (NSArray *)personsWithName:(NSString *)name { // 如果在NSString中包含%,可以使用%%表示 NSString *sql = [NSString stringWithFormat:@"SELECT id, name, age, phoneNo FROM t_person WHERE name LIKE '%%%@%%'", name]; // 调用自定义方法queryPersonsWithSql return [self queryPersonsWithSql:sql]; } /** * 自定义方法:根据指定sql查询person记录,返回对象数组 * @param sql sql * @return 结果集,返回对象数组 */ - (NSArray *)queryPersonsWithSql:(NSString *)sql { // 1. 评估准备SQL语法是否正确 sqlite3_stmt *stmt = NULL; NSMutableArray *persons = nil; // sqlite3_prepare_v2()方法,参数1:sqlite3连接(句柄) // 参数2:c类型的sql文本 // 参数3:限制sql语句的最长字节数,-1代表不限制 // 参数4:指向sqlite3_stmt的指针的地址 // 参数5:指向未使用的sql语句的一部分???? if (SQLITE_OK == sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL)) { // 2. 如果能够正常查询,persons才实例化 persons = [NSMutableArray array]; // 调用单步执行方法,依次取得查询结果 // sqlite3_step()方法:参数1:statement....对象stmt // 返回值:int类型的SQLITE_ROW代表,得到一行记录 while (SQLITE_ROW == sqlite3_step(stmt)) { // 3. 获取/显示查询结果 // sqlite3_column_xxx()方法: // 参数1:statement....对象stmt // 参数2:哪一列(字段索引),与sql语句中的字段顺序一一对应(从0开始) int ID = sqlite3_column_int(stmt, 0); // 指针,指向的内容不可变 const unsigned char *name = sqlite3_column_text(stmt, 1); int age = sqlite3_column_int(stmt, 2); // 指针,指向的内容不可变 const unsigned char *phoneNo = sqlite3_column_text(stmt, 3); // c字符串,转成OC中字符串 NSString *nameUTF8 = [NSString stringWithUTF8String:(const char *)name]; NSString *phoneNoUTF8 = [NSString stringWithUTF8String:(const char *)phoneNo]; Person *p = [Person personWithID:ID name:nameUTF8 age:age phoneNo:phoneNoUTF8]; [persons addObject:p]; } } else { NSLog(@"SQL语法错误"); } // 4. 最后,千万记得,结束/释放句柄 sqlite3_finalize(stmt); return persons; } @end
// Person.h // 02.SQLite基本使用 // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. #import <Foundation/Foundation.h> @interface Person : NSObject /** * 工厂方法 * * @param ID ID * @param name 姓名 * @param age 年龄 * @param phoneNo 电话 * * @return 个人信息对象 */ + (id)personWithID:(NSInteger)ID name:(NSString *)name age:(NSInteger)age phoneNo:(NSString *)phoneNo; @property (assign, nonatomic) NSInteger ID; @property (strong, nonatomic) NSString *name; @property (assign, nonatomic) NSInteger age; @property (strong, nonatomic) NSString *phoneNo; @end
// Person.m // 02.SQLite基本使用 // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. #import "Person.h" @implementation Person + (id)personWithID:(NSInteger)ID name:(NSString *)name age:(NSInteger)age phoneNo:(NSString *)phoneNo { Person *p = [[Person alloc] init]; p.ID = ID; p.name = name; p.age = age; p.phoneNo = phoneNo; return p; } - (NSString *)description { return [NSString stringWithFormat:@"<Person: %p, ID: %d, name: %@, age: %d, phoneNo: %@>", self, _ID, _name, _age, _phoneNo]; } @end
// // ViewController.h // 02.SQLite基本使用 // // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController @end
// ViewController.m // 02.SQLite基本使用 // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. #import "ViewController.h" #import "Person.h" #import "PersonManager.h" @interface ViewController () <UITableViewDataSource, UISearchBarDelegate> { NSArray *_personList; } @property (weak, nonatomic) IBOutlet UITableView *tableView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 调用单例,PersonDao查询所有个人信息 _personList = [[PersonManager sharedPersonManager] allPersons]; } #pragma mark - 表格数据源方法 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _personList.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"Cell"; // 在iOS 6中,如果使用registercell,系统会在runtime自动注册可重用单元格 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath]; if(cell == nil){ //cell=....,,ID; } // 填充独一无二的数据 Person *p = _personList[indexPath.row]; cell.textLabel.text = p.name; cell.detailTextLabel.text = p.phoneNo; return cell; } #pragma mark - 搜索栏代理方法,回车后调用 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { _personList = [[PersonManager sharedPersonManager] personsWithName:searchText]; // 先数据模型修改 // 然后重新加载,整体刷新 [_tableView reloadData]; } @end
// // NSArray+Log.h // // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. // #import <Foundation/Foundation.h> // 新增一个分类 @interface NSArray (Log) @end
// NSArray+Log.m // Created by apple on 13-11-24. // Copyright (c) 2013年 itcast. All rights reserved. #import "NSArray+Log.h" @implementation NSArray (Log) - (NSString *)descriptionWithLocale:(id)locale { NSMutableString *strM = [NSMutableString stringWithFormat:@"%d (\n", self.count]; [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [strM appendFormat:@"\t%@", obj]; if (idx < self.count - 1) { [strM appendString:@",\n"]; } }]; [strM appendString:@"\n)"]; return strM; } @end
/*单例宏的使用方法三步曲: 1,PersonManager.h文件中导入Singleton.h #import "Singleton.h" 2,PersonManager.h文件中 single_interface(PersonManager) 3,PersonManager.m文件中 single_implementation(PersonManager) */ // .h #define single_interface(class) + (class *)shared##class; // .m // \ 代表下一行也属于宏 // ## 是分隔符 #define single_implementation(class) \ static class *_instance; \ \ + (class *)shared##class \ { \ if (_instance == nil) { \ _instance = [[self alloc] init]; \ } \ return _instance; \ } \ \ + (id)allocWithZone:(NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \ }