我正在使用FMDB在iPhone上创建SQLite数据库。我有一个形式为
的initial.sqlCREATE TABLE Abc ... ;
CREATE TABLE Def ... ;
我通过将文件加载到NSString并运行它来加载它
NSString * str = // string from file initial.sql
[db executeUpdate: str];
这成功但后来我失败了:
no such table: Def
很明显,第二个声明没有被调用。我该怎么做才能调用所有查询?
根据SQLite文档: “例程sqlite3_prepare_v2(),sqlite3_prepare(),sqlite3_prepare16(),sqlite3_prepare16_v2(),sqlite3_exec()和sqlite3_get_table()接受一个SQL语句列表(sql-stmt-list),它是一个以分号分隔的语句列表。”
所以,这一切都应该有效。
答案 0 :(得分:8)
我也被这个人咬了;我花了一整个上午踩过FMDatabase并阅读sqlite3 API文档来找到它。我仍然不完全确定问题的根本原因,但根据this bug in PHP,有必要调用sqlite3_exec而不是使用sqlite3_prepare_v2准备语句,然后调用sqlite3_step。
文档似乎没有暗示这种行为会发生,因此我们的困惑,我希望有更多经验的sqlite能够提出一些假设。
我通过开发一种执行一批查询的方法解决了这个问题。请在下面找到代码。如果您愿意,可以将其重写为一个类别,而不是仅将其添加到您的调用FMDatabase.h中。
将其添加到FMDatabase.h中的FMDatabase接口:
- (BOOL)executeBatch:(NSString*)sql error:(NSError**)error;
将其添加到FMDatabase.m中的FMDatabase实现:
- (BOOL)executeBatch:(NSString *)sql error:(NSError**)error
{
char* errorOutput;
int responseCode = sqlite3_exec(db, [sql UTF8String], NULL, NULL, &errorOutput);
if (errorOutput != nil)
{
*error = [NSError errorWithDomain:[NSString stringWithUTF8String:errorOutput]
code:responseCode
userInfo:nil];
return false;
}
return true;
}
请注意,executeBatch中缺少许多功能,因此不适合用于很多目的。具体来说,它不检查数据库是否被锁定,它不确保FMDatabase本身没有被锁定,它不支持语句缓存。
如果您需要,上面是自己编写代码的好起点。快乐的黑客!
答案 1 :(得分:8)
FMDB v2.3现在有一个名为executeStatements
的sqlite3_exec
原生包装:
BOOL success;
NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);"
"create table bulktest2 (id integer primary key autoincrement, y text);"
"create table bulktest3 (id integer primary key autoincrement, z text);"
"insert into bulktest1 (x) values ('XXX');"
"insert into bulktest2 (y) values ('YYY');"
"insert into bulktest3 (z) values ('ZZZ');";
success = [db executeStatements:sql];
它还有一个使用sqlite3_exec
回调的变体,实现为块:
sql = @"select count(*) as count from bulktest1;"
"select count(*) as count from bulktest2;"
"select count(*) as count from bulktest3;";
success = [db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) {
NSInteger count = [dictionary[@"count"] integerValue];
NSLog(@"Count = %d", count);
return 0; // if you return 0, it continues execution; return non-zero, it stops execution
}];
答案 2 :(得分:2)
Split Batch Statement
Add in .h file:
#import "FMSQLStatementSplitter.h"
#import "FMDatabaseQueue.h"
FMSQLStatementSplitter can split batch sql statement into several separated statements, then [FMDatabase executeUpdate:] or other methods can be used to execute each separated statement:
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
NSString *batchStatement = @"insert into ftest values ('hello;');"
@"insert into ftest values ('hi;');"
@"insert into ftest values ('not h!\\\\');"
@"insert into ftest values ('definitely not h!')";
NSArray *statements = [[FMSQLStatementSplitter sharedInstance] statementsFromBatchSqlStatement:batchStatement];
[queue inDatabase:^(FMDatabase *adb) {
for (FMSplittedStatement *sqlittedStatement in statements)
{
[adb executeUpdate:sqlittedStatement.statementString];
}
}];