FMDB:添加新列并插入数据

时间:2014-01-01 15:32:15

标签: objective-c sqlite fmdb

在我的应用中,我正在使用FMDatabase。我正在尝试向该列中的现有columntable数据添加新的insert。当我按Alter Table添加列时,我没有错误,但是当我尝试在表中插入数据时,我收到错误抱怨新添加的列不存在。

这是我的代码

NSString *databasePath = [myDB getPlacesDBPath];

FMDatabase *db = [FMDatabase databaseWithPath:databasePath];

if (![db open])
{
    return ;
}

if (![db columnExists:@"placeName" inTableWithName:@"MYPLACES"])
{
    [db executeQuery:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];
    // I tried to set the result of this query in "BOOL Success" and print the results and I got YES    
}

//Note: I have more than 12 columns but I didn't post all of them here
NSString *insertSQL = [NSString stringWithFormat: @"INSERT INTO  MYPLACES  ( placeID ,  placeName)  VALUES (\"%@\", \"%@\")", placeIDValue, placeNameValue ];

[db executeUpdate:insertSQL];

if ([db hadError]) {
    NSLog(@"error : %@",[db lastError]);
}

[db close];

我收到以下错误:

error : Error Domain=FMDatabase Code=1 "table MYPLACES has no column named placeName" UserInfo=0xe340920 {NSLocalizedDescription=table MYPLACES has no column named placeName}

有什么问题?如何知道为什么没有添加新列?

3 个答案:

答案 0 :(得分:14)

我在上面的简化代码示例中没有看到任何内容来解释您报告的错误。问题可能在其他地方(或者,在简化代码示例的过程中,您消除了问题的根源)。

有人说过,我有几个反应:

  1. 你说:

      

    我尝试在“BOOL Success”中设置此查询的结果并打印结果,我得到了

    我不知道这是怎么回事,因为executeQuery会返回FMResultSet而不是BOOL。不过,这是没有意义的,因为ALTER TABLE语句应该使用executeUpdate而不是executeQuery来执行。 (后者应该仍然有效,但前者更合乎逻辑。)

  2. 我不明白为什么你删除了错误检查。这是识别问题的最佳方式。

  3. 完全不相关,但在构建SQL时不应使用stringWithFormat。您可以打开由于意外输入导致的SQL失败(例如,如果您的某个值在其中有双引号,那么该怎么办)。更糟糕的是,你暴露自己的SQL注入攻击。相反,在SQL中使用?占位符,然后将值作为参数传递给executeUpdate(或executeQuery)方法。

  4. 所以,以下代码对我来说很好:

    BOOL success;
    
    FMDatabase *db = [FMDatabase databaseWithPath:databasePath];
    
    if (![db open])
    {
        NSLog(@"open failed");
        return;
    }
    
    if (![db columnExists:@"placeName" inTableWithName:@"MYPLACES"])
    {
        success = [db executeUpdate:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];
        NSAssert(success, @"alter table failed: %@", [db lastErrorMessage]);
    }
    
    NSString *insertSQL = @"INSERT INTO  MYPLACES  (placeID, placeName)  VALUES (?, ?)";
    success = [db executeUpdate:insertSQL, placeIDValue, placeNameValue];
    NSAssert(success, @"insert failed: %@", [db lastErrorMessage]);
    
    [db close];
    

    由于我没有看到导致您描述的问题的原因,我只建议您在调试器中单步执行此代码,并确保它遵循您认为的路径。

答案 1 :(得分:1)

Swift 3代码:

 let db = FMDatabase(path: Util.getPath(databasePath)
    guard db != nil else { return }

    db!.open()
    if !(db!.columnExists("tableName", columnName: "USERID")) {

        let alterTable = "ALTER TABLE tableName ADD COLUMN USERID TEXT"
        if db!.executeUpdate(alterTable, withArgumentsIn: nil) {
            printf(“new column added”)
    }
    else {
        printf(“issue in operation”)
    }
    db!.close()
可能会帮助别人。 继续编码..

答案 2 :(得分:0)

问题在于-[FMDatabase executeQuery:]不执行提交的指令,它仅准备语句。

要执行它们,您需要执行一个“步骤”。

在FMDB中,通过-[FMResultSet next]在内部-通过调用sqlite3_step()完成。

由于-executeUpdate :(与-executeQuery:相反)为您完成了该任务并完成了语句,因此可能更适合此目的。

因此,如果您确实需要使用-executeQuery:

FMResultSet *rs = [db executeQuery:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];
[rs nextWithError:&error]; // error handling is recommended here
[rs close];

但是-executeUpdate:更简洁

BOOL success = [db executeUpdate:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];