IOS_SQLite_单例宏_NSArray+Log

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



H:/1124/01_Book.h
//
//  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

H:/1124/01_Book.m
//
//  Book.m
//  数据库关系
//
//  Created by apple on 13-11-24.
//  Copyright (c) 2013年 itcast. All rights reserved.
//

#import "Book.h"

@implementation Book

@end

H:/1124/01_Student.h
//
//  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

H:/1124/01_Student.m
//
//  Student.m
//  数据库关系
//
//  Created by apple on 13-11-24.
//  Copyright (c) 2013年 itcast. All rights reserved.
//

#import "Student.h"

@implementation Student

@end

H:/1124/02_SQLite_DAO_PersonManager.h
//  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

H:/1124/02_SQLite_DAO_PersonManager.m
//  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

H:/1124/02_SQLite_model_Person.h
//  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

H:/1124/02_SQLite_model_Person.m
//  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

H:/1124/02_SQLite_ViewController.h
//
//  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

H:/1124/02_SQLite_ViewController.m
//  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

H:/1124/02_tool分类_描述_NSArray+Log.h
//
//  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

H:/1124/02_tool分类_描述_NSArray+Log.m
//  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

H:/1124/02_tool单例宏模板_Singleton.h
/*单例宏的使用方法三步曲:
	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; \
}

你可能感兴趣的:(ios,sqlite,单例宏,NSArray+Log)