• 昨天做一个需求,参数的数量不确定,所以无法使用这个API:

    - (BOOL)executeUpdate:(NSString*)sql, ...

    但是用

    - (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments

    可以很方便地处理这个场景,本文总结一下

    两类insert语句

    因为不管使用哪种API,都需要先拼接sql语句,所以先了解一下sql insert语句的写法。有2种,比较常见的是指定列名的insert:

    insert into table_name (c1,c2,c3) values (v1,v2,v3);

    如果自己指定了目标列名,那么插入的列的数量可以少于table schema,列的顺序也可以任意指定。第2种是不指定列名的insert:

    insert into table_name values (v1,v2,v3);
     

    这种写法不需要自己指定列名,比较方便,但是values里需要包含所有的列,而且顺序要和table schema一致

    FMDB的2种常用API

    我自己比较常用的FMDB API有2个。如果参数的数量是确定的,而且不多,可以用这个API:

    NSString *sql = @"insert into users values(:id, :name, :age)";
    [db executeUpdate:sql, id, name, age];

    上面的代码用了:key的语法,或者用?,效果也是一样的

    NSString *sql = @"insert into users values(?,?,?)";
    [db executeUpdate:sql, id, name, age];

    另外一种场景,是参数的数量不确定,或者参数数量非常多,那上面这个API就不太方便,FMDB提供了另一个API,允许传入一个NSDictionary作为参数:

    NSString *sql = @"insert into users values(:id, :name, :age)";
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"id123", @"id", @"kyfxbl", @"name", , @"age", nil];
    [db executeUpdate:sql withParameterDictionary:dict];

    注意Dictionary里的key需要和sql里的:key一致,FMDB根据key值来决定如何绑定

    遇到的问题

    我昨天就是用上面的第二种API来实现,不过遇到一个错误,总是报table_name.id may not be NULL。最后发现原因,是拼的sql采用了不指定列名的方式,类似于:

    NSString *sql = @"insert into table_name values (:k1,:k2,:k3)";

    然后刚好NSDictionary里元素的顺序又是错的,第一个元素的值是null,造成id为空,插入失败。其实关键不在于FMDB,而是sql没拼对。主要是我不了解FMDB的这个API,我以为它会自己处理顺序,实际上,FMDB不处理SQL拼接,只处理参数变量替换

    有2个办法可以解决这个问题,一个办法是调整Dictionary里元素的顺序,使它和table schema列定义的顺序一致,不过比较困难。另一个办法就是重新拼sql,指定好列名

    实际的代码

    下面是实现的代码,删除了无关代码,以免干扰

    -(void) handleJsonObject:(NSDictionary*) tableName
    {
    NSString *sql = [self assembleInsertSql:tableName];// 拼装sql语句:insert into table_name (c1,c2,c3) values (:a,:b,:c); if(!sql){
    return;// 说明data里无数据,不需要操作数据库
    } NSString *dbFilePath = [YLSGlobalUtils getDatabaseFilePath];
    FMDatabase *db = [FMDatabase databaseWithPath:dbFilePath];
    [db open]; NSArray *datas = [tableName objectForKey:@"data"];
    for(NSDictionary *data in datas){
    NSMutableDictionary *mutable = [NSMutableDictionary dictionaryWithDictionary:data];
    [mutable removeObjectForKey:@"_id"];
    BOOL result = [db executeUpdate:sql withParameterDictionary:mutable];
    if(!result){
    NSLog([NSString stringWithFormat:@"%d", [db lastErrorCode]], nil);
    NSLog([db lastErrorMessage], nil);
    }
    } [db close];
    } // 返回格式:insert into table_name (c1,c2,c3) values (:a,:b,:c);
    -(NSString*) assembleInsertSql:(NSDictionary*) tableName
    {
    NSArray *datas = [tableName objectForKey:@"data"]; if([datas count] == ){
    return nil;
    } NSDictionary *record = [datas objectAtIndex:];// 取出第一条记录,为了拿到列名
    NSArray *columns = [record allKeys]; NSString *table = [tableName objectForKey:@"tableName"];
    NSString *prefix = [NSString stringWithFormat:@"insert into %@ (", table]; NSMutableString *middle = [NSMutableString new];
    for(int i=;i<[columns count];i++){
    NSString *columnName = [columns objectAtIndex:i];// 列名
    if(![@"_id" isEqualToString:columnName]){
    [middle appendString:columnName];
    [middle appendString:@","];
    }
    }
    NSString* cuttedMiddle = [YLSGlobalUtils removeLastOneChar:middle]; NSMutableString *suffix = [NSMutableString new];
    [suffix appendString:@") values ("];
    for(int i=;i<[columns count];i++){
    NSString *columnName = [columns objectAtIndex:i];// 列名
    if(![@"_id" isEqualToString:columnName]){
    [suffix appendString:@":"];
    [suffix appendString:columnName];
    [suffix appendString:@","];
    }
    }
    NSString *cuttedSuffix = [YLSGlobalUtils removeLastOneChar:suffix]; NSMutableString *sql = [NSMutableString new];
    [sql appendString:prefix];
    [sql appendString:cuttedMiddle];
    [sql appendString:cuttedSuffix];
    [sql appendString:@");"];
    return sql;
    }

    通过上面拼接sql的方法,虽然NSDictionary里的元素顺序不确定,但是列名和values里的顺序总是保证一致的,不会影响最后的插入

FMDB处理动态插入语句的更多相关文章

  1. MyBatis的动态插入语句(经常报‘无效的列类型’)

    最近在工作中经常遇到一个情况:通过mybatis的标签执行插入语句,当表中字段比较多的时候,需要全部插入,而有时候的需求是只插入其中几个字段,但是会报错. 原来的语句,必须把所有字段都Set值. &l ...

  2. 动态sql语句基本语法--Exec与Exec sp_executesql 的区别

    http://www.cnblogs.com/goody9807/archive/2010/10/19/1855697.html 动态sql语句基本语法 1   :普通SQL语句可以用Exec执行   ...

  3. MyBatis学习(三)、动态SQL语句

    三.动态SQL语句 有些时候,sql语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可能是空的,也许我们需要参数为空时,是查出全部的信息.使用Orac ...

  4. 三、动态SQL语句

    //备注:该博客引自:http://limingnihao.iteye.com/blog/106076 有些时候,sql语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空, ...

  5. 存储过程中执行动态Sql语句

    MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql;通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有.还有一个最大的好处就 ...

  6. MyBatis学习总结_11_MyBatis动态Sql语句

    MyBatis中对数据库的操作,有时要带一些条件,因此动态SQL语句非常有必要,下面就主要来讲讲几个常用的动态SQL语句的语法 MyBatis中用于实现动态SQL的元素主要有: if choose(w ...

  7. 【转】Hibernate利用@DynamicInsert和@DynamicUpdate生成动态SQL语句

    原文链接:http://www.cnblogs.com/quanyongan/p/3152290.html 最近在使用Hibernate4中,发现两个很有奥秘的注解 @DynamicInsert 和  ...

  8. Oracle基础 动态SQL语句

    一.静态SQL和动态SQL的概念. 1.静态SQL 静态SQL是我们常用的使用SQL语句的方式,就是编写PL/SQL时,SQL语句已经编写好了.因为静态SQL是在编写程序时就确定了,我们只能使用SQL ...

  9. MyBatis学习 之 三、动态SQL语句

    目录(?)[-] 三动态SQL语句 selectKey 标签 if标签 if where 的条件判断 if set 的更新语句 if trim代替whereset标签 trim代替set choose ...

随机推荐

  1. 如何去定义一个jquery插件

    扩展jquery的时候.最核心的方法是以下两种: $.extend(object) 可以理解为jquery添加一个静态方法 $.fn.extend(object) 可以理解为jquery实例添加一个方 ...

  2. 【代码笔记】iOS-3DES+Base64加密解密

    一,工程目录. 二,代码. RootViewController.m #import "RootViewController.h" #import "NSString+T ...

  3. 【Android】不依赖焦点和选中的TextView跑马灯

    前言 继承TextView,并仿照源码修改而来,主要是取消了焦点和选中了判断,也不依赖文本的宽度. 声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblogs.com 农民 ...

  4. iOS 远程推送通知

    1.什么是推送通知 在某些特殊情况下,应用程序被动收到的以不同种界面形式出现的提醒信息 推送通知的作用:可以让不在前台运行的app通知app发生了改变 iOS中得推送通知种类 远程推送通知(Remot ...

  5. redis配置文件参数说明及命令操作

    redis下载地址:https://github.com/MSOpenTech/redis/releases. Redis 的配置文件位于 Redis 安装目录下,文件名为redis.windows. ...

  6. 关于 python

    关于python的版本: python2.7  和 python3.0 有很大的不同,学习时应因目的而做出选择. 目前用到的python2.7最多, 而web3.0时代 则用到的python3.0 所 ...

  7. ArrayList vs LinkedList vs Vector

    List概览 List,正如它的名字,表明其是有顺序的.当讨论List的时候,最好拿它跟Set作比较,Set中的元素是无序且唯一:下面是一张类层次结构图,从这张图中,我们可以大致了解java集合类的整 ...

  8. C#语句1:选择语句二(switch break)

    (二)switch case switch case 必须与 break 一同使用.break是跳转语句.与switch case连用的时候是跳出最近的{}. 注: ●若case后面接收的是字符串类型 ...

  9. 教你手工mysql拆库

    互联网网站应用大多采用mysql作为DB存储,限于mysql单机性能的瓶颈,为了支撑更大容量和更大的访问量,dba一般通过建立分布式集群,让多个mysql共同提供服务.所谓的mysql分布式集群,实质 ...

  10. 【hbase】——HBase 写优化之 BulkLoad 实现数据快速入库

    1.为何要 BulkLoad 导入?传统的 HTableOutputFormat 写 HBase 有什么问题? 我们先看下 HBase 的写流程: 通常 MapReduce 在写HBase时使用的是 ...