8

我正在使用 FMDB 在 iPhone 上创建 SQLite 数据库。我有一个 initial.sql 的形式

CREATE 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),它是一个分号-分隔的语句列表。”

所以,这一切都应该奏效。

4

3 回答 3

8

我也被这个咬了;我花了整个上午的时间浏览 FMDatabase 并阅读 sqlite3 API 文档来找到它。我仍然不完全确定问题的根本原因,但是根据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 本身没有被锁定,它不支持语句缓存。

如果您需要,上面是您自己编写代码的一个很好的起点。快乐黑客!

于 2011-11-18T10:47:41.330 回答
8

sqlite3_execFMDB v2.3 现在有一个名为的本机包装器executeStatements

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
}];
于 2014-05-04T01:39:53.823 回答
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];
    }
}];
于 2014-04-21T12:56:55.720 回答