【问题标题】:Objective-C compacting several SQL statementsObjective-C 压缩几个 SQL 语句
【发布时间】:2014-06-17 21:49:20
【问题描述】:

我有一个与 SQL 数据库对话的应用程序,示例表由 OBSERVATIONSID(主键)、LEVEL0、LEVEL1、LEVEL2、LEVEL3、LEVEL4、EDITABLE 组成。

目前每次我想排,我 读取数据库以确保行不存在。 存储数据 再次读取数据库以获取刚刚添加的主键。

存储数据

+ (void) ObservationsEditSaveData : (NSString*) Level1 : (NSString*) Level2 : (NSString*)Level3 : (NSString*) Level4 : (NSString*) Level0{
    sqlite3_stmt *updateStmt;

    sqlite3_open([dbObservationPathString UTF8String], &ObservationDB);
    NSString* updateSQL = [NSString stringWithFormat: @"INSERT INTO OBSERVATIONS(LEVEL0, LEVEL1, LEVEL2, LEVEL3, LEVEL4, EDITABLE)  values (?,?,?,?,?,?)"];

    sqlite3_prepare_v2(ObservationDB, [updateSQL UTF8String], -1, &updateStmt, NULL);
    if(sqlite3_step(updateStmt)==SQLITE_DONE)
    {
        sqlite3_bind_text(updateStmt, 1, [Level0 UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(updateStmt, 2, [Level1 UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(updateStmt, 3, [Level2 UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(updateStmt, 4, [Level3 UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(updateStmt, 5, [Level4 UTF8String], -1, SQLITE_TRANSIENT);
        sqlite3_bind_int(updateStmt, 6, 0);
        sqlite3_step(updateStmt);
        sqlite3_finalize(updateStmt);
    }
    sqlite3_close(ObservationDB);
}

读取 ID / 检查是否存在。 (在检查是否存在时,如果返回 ID,我假设它存在)

+ (int) ObservationGetID : (NSString*) Level1 : (NSString*) Level2 : (NSString*) Level3 : (NSString*) Level4 : (NSString*) Level0{
    int ReturnValue = 0;
    sqlite3_stmt *statement;

    if (sqlite3_open([dbObservationPathString UTF8String], &ObservationDB)==SQLITE_OK)
    {
        NSString *querySql = [NSString stringWithFormat:@"SELECT OBSERVATIONSID FROM OBSERVATIONS WHERE LEVEL0 = '%@' AND LEVEL1 = '%@' AND LEVEL2 = '%@' AND LEVEL3 = '%@' AND LEVEL4 = '%@'", Level0 ,Level1, Level2, Level3, Level4];
        const char* query_sql = [querySql UTF8String];

        if (sqlite3_prepare(ObservationDB, query_sql, -1, &statement, NULL)==SQLITE_OK)
        {
            while (sqlite3_step(statement)==SQLITE_ROW)
            {
                 ReturnValue = sqlite3_column_int(statement, 0);
            }
        }
    }
    sqlite3_close(ObservationDB);
    return ReturnValue;
}

id喜欢做的是减少sql调用的次数,我可以把这些命令合二为一吗?

顺便说一句,如果我把代码弄乱了,请说,我不会被冒犯的。

谢谢

【问题讨论】:

  • 顺便说一句,您的observationGetID 方法可能应该使用sqlite3_bind_xxx 函数,就像您在observationsEditSaveData 中所做的那样。您永远不想使用stringWithFormat 构建 SQL。如果你觉得这样的绑定值太麻烦,可以考虑使用FMDB,这样可以更轻松地编写可靠的 SQLite 代码。此外,通常建议您只打开一次数据库,而不是在每次方法调用时打开和关闭它。
  • 所以要做到这一点,我会 sqlite3_step 然后做所有的绑定吗?然后有 while (sqlite3_step(statement)==SQLITE_ROW) { ReturnValue = sqlite3_column_int(statement, 0);我很困惑 sqlite3_bind_text 和 sqlite3_column_int 是如何结合在一起的
  • 参见下面的代码示例。最重要的是,step 函数将实际执行 SQL。但很明显,在绑定值之前,您不想执行 SQL。所以先绑定,再一步。
  • observationGetID 中,您将sqlite3_prepare_v2sqlite3_bind_xxx 用于WHERE 子句的所有列,然后让您的while (sqlite3_step(statement) == SQLITE_ROW) 循环在其中检索带有@ 的列987654333@.
  • 是的,这很有道理,我对做了什么感到困惑。那里有很多不明确的建议

标签: objective-c sqlite ipad


【解决方案1】:

您在绑定值之前调用sqlite3_step(在您的if 子句中)。您必须先绑定值,然后才能使用sqlite3_step 执行 SQL。只需删除带有sqlite3_stepif 子句即可。


您可以更改observationsEditSaveData 方法,以便:

  1. step 函数之前调用bind 函数。

  2. 让函数返回插入行的行 ID(零表示有错误)。

  3. 检查所有 SQLite 调用的结果。

  4. 符合Cocoa naming conventions(以小写字母开头的方法和变量名)。

这会产生:

+ (sqlite3_int64) observationsEditSaveData : (NSString*) level1 : (NSString*) level2 : (NSString*)level3 : (NSString*) level4 : (NSString*) level0 {
    sqlite3_stmt *updateStmt;

    if (sqlite3_open([dbObservationPathString UTF8String], &observationDB) != SQLITE_OK) {
        NSLog(@"open failed");
        return 0;
    }

    const char *updateSQL = "INSERT INTO OBSERVATIONS(LEVEL0, LEVEL1, LEVEL2, LEVEL3, LEVEL4, EDITABLE)  values (?,?,?,?,?,?)";

    if (sqlite3_prepare_v2(observationDB, updateSQL, -1, &updateStmt, NULL) != SQLITE_OK)
        NSLog(@"prepare failed: %s", sqlite3_errmsg(observationDB));
    if (sqlite3_bind_text(updateStmt, 1, [level0  UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        NSLog(@"bind 1 failed: %s", sqlite3_errmsg(observationDB));
    if (sqlite3_bind_text(updateStmt, 2, [level1  UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        NSLog(@"bind 2 failed: %s", sqlite3_errmsg(observationDB));
    if (sqlite3_bind_text(updateStmt, 3, [level2  UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        NSLog(@"bind 3 failed: %s", sqlite3_errmsg(observationDB));
    if (sqlite3_bind_text(updateStmt, 4, [level3  UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        NSLog(@"bind 4 failed: %s", sqlite3_errmsg(observationDB));
    if (sqlite3_bind_text(updateStmt, 5, [level4  UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        NSLog(@"bind 5 failed: %s", sqlite3_errmsg(observationDB));
    if (sqlite3_bind_int(updateStmt, 6, 0))
        NSLog(@"bind 1 failed: %s", sqlite3_errmsg(observationDB));
    if (sqlite3_step(updateStmt) != SQLITE_DONE)
        NSLog(@"step failed: %s", sqlite3_errmsg(observationDB));
    sqlite3_finalize(updateStmt);

    sqlite3_int64 rowid = sqlite3_last_insert_rowid(observationDB);

    sqlite3_close(observationDB);

    return rowid;
}

【讨论】:

  • 有什么办法可以很容易地调整它,它会在添加之前检查该行不存在,我读过“如果不存在则插入”,但在我的尝试中它完全失败了
  • @user1603332 你可以先打电话给observationGetID,看看有没有价值,如果没有,再打电话给你的observationsEditSaveData。也许我不明白这个问题。
  • 不,这就是我在 atm 上做的方式,但想知道是否有一种方法可以将它合并到一个 sql 调用中,只是为了更好地编码
  • 只是调用数据库查看是否存在似乎很愚蠢,如果不调用数据库放入数据,则最后再次调用数据库以获取我刚刚放入的数据的ID。
  • @user1603332 有INSERT OR REPLACE的语法,不过是用主键决定的,这里不适用。有些人可能倾向于(a)在桌子上放一个备用的唯一键;和(b)只是INSERT(忽略它是否已经存在并产生错误),但我认为这不是一个好习惯。不过,在获取唯一 ID 方面,您不必重新SELECT。你可以直接调用sqlite3_last_insert_rowid(假设OBSERVATIONSID被定义为INTEGER PRIMARY KEY AUTOINCREMENT)。
猜你喜欢
  • 1970-01-01
  • 2016-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
  • 2012-01-08
  • 2018-12-06
相关资源
最近更新 更多