【问题标题】:How to update an entry in sqlite3?如何更新sqlite3中的条目?
【发布时间】:2013-10-10 18:30:11
【问题描述】:

我是 ios (Objective-C) 和 sql 的超级新手,我按照这里的 sqlite(特别是 sqlite3)教程进行操作:http://www.tutorialspoint.com/ios/ios_sqlite_database.htm 我正确地实施了一切。问题是,如果我尝试使用相同的 reg id(用于在数据库中查找元素的主键)输入信息,它会抱怨该键不是唯一的。

- (BOOL) saveData:(NSString*)registerNumber name:(NSString*)name
   department:(NSString*)department year:(NSString*)year;
    {
    const char *dbpath = [databasePath UTF8String];
    if (sqlite3_open(dbpath, &database) == SQLITE_OK)
    {
        NSString *insertSQL =
        [NSString stringWithFormat:@"insert into studentsDetail (regno,name, department, year) values (\"%d\",\"%@\", \"%@\", \"%@\")",[registerNumber integerValue], name, department, year];

        const char *insert_stmt = [insertSQL UTF8String];
        sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
        int s = sqlite3_step(statement);
        const char *errmsg = sqlite3_errmsg(database);
        if (s == SQLITE_DONE)
        {
            sqlite3_reset(statement);
            return YES;
        }
        else {
            sqlite3_reset(statement);
            return NO;
        }
    }
    return NO;
}

如何进行 saveData: 操作实际更新数据库中的条目,而不是仅仅被拒绝? 谢谢!

【问题讨论】:

  • 数值不加引号。并且字符串值必须用单引号,而不是双引号。但更重要的是,不要使用stringWithFormat 来构建您的查询。使用sqlite3_bind_xxx 正确绑定值。
  • 由于每次都打开数据库,所以还需要关闭数据库。您还应该完成声明。无需重置语句,因为您没有重用它们。您还需要检查sqlite3_prepare_v2 的返回值。使用sqlite3_errmsg() 检查任何失败的呼叫。
  • @rmaddy 代码按照最初的预期工作,引入了一个简单的 sql 数据库结构,但我想扩展它,以便如果我尝试输入现有的 reg id,它将覆盖其余属性与新属性。我会考虑使用绑定函数,但就格式而言,我相当确定对于 obj-c,我对字符串和数字使用了正确的语法,但如果我错了,请纠正我。
  • 使用 FMDatabase 框架,很容易在表中插入值。

标签: ios sqlite sql-update


【解决方案1】:

“我想扩展它,这样如果我尝试输入现有的 reg id,它 将用新的属性覆盖剩余的属性”

如果这是您想要完成的,那么您不应该使用 INSERT 语句。主键的目的是保护数据库免受具有相同主键的重复行的影响。当你这样看时,拒绝是恰当的。

你真正想要的是使用INSERT OR REPLACE

如果您是 sql 和 Objective c 的初学者,我会推荐我创建的针对初学者的 sqlite 包装器:TankDB

编辑:

代码示例:

插入或替换学生详细信息(regno、姓名、部门、​​年份)值(\"%d\"、\"%@\"、\"%@\"、\"%@\")"

请参阅this question 以确保您实际上并不是要使用“UPSERT”。请注意,INSERT OR REPLACE 不会使用新信息更新现有行。它将完全删除现有行并替换它。

Edit2:打开、准备、步骤、完成、关闭

const char *dbpath = [_databasePath UTF8String];
if(sqlite3_open(dbpath, &_database) == SQLITE_OK) {
    const char *command = [query UTF8String];

    // Perform the query
    if (sqlite3_prepare_v2(_database, command, -1, &selectstmt, NULL) == SQLITE_OK) {

        // For each row returned
        while (sqlite3_step(selectstmt) == SQLITE_ROW) {
            // Do stuff
        }
    }
    sqlite3_finalize(selectstmt);
}

sqlite3_close (_database);

【讨论】:

  • 如何更改我的代码以使其使用 REPLACE? insert_stmt?
  • 如果 INSERT OR REPLACE 只是删除和重新插入,主键会改变,但除此之外,功能是否相同?这正是我一直在寻找的,感谢您帮助我意识到我做错了什么
  • 没问题。如果它有助于解决您的问题,最好将答案标记为已接受的答案。
  • 我尝试用 INSERT OR REPLACE 替换我的插入,现在我得到一个 errmsg 的数据库被锁定。你知道为什么会这样吗?
  • 是的,正如上面提到的 rmaddy,您永远不会完成您的声明或关闭您的数据库。您需要确保在每次调用 saveData 结束时关闭数据库。添加关闭时要小心,因为您的函数中有多个返回语句。无论您的代码采用哪个分支,您都需要确保调用 close 语句。
猜你喜欢
  • 2016-02-21
  • 2018-04-04
  • 2022-12-10
  • 2019-11-08
  • 1970-01-01
  • 2016-12-28
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多