在迭代结果集时删除sqlite3中的当前行

时间:2011-02-08 02:44:09

标签: c sqlite

是否可以迭代结果集,如果满足条件,则删除当前行?

即。

之类的东西
int rc;
sqlite3_stmt* statement;
sqlite3_exec(db, "BEGIN", 0, 0, 0);

sqlite3_prepare_v2(_db, "SELECT id,status,filename,del FROM mytable", -1, &statement, NULL);

rc = sqlite3_step(statement);
while (rc == SQLITE_ROW){
  int id = sqlite3_column_int(statement, 1);
  int status = sqlite3_column_int(statement, 2);
  const unsigned char* filename = sqlite3_column_int(statement, 3);
  int del = sqlite3_column_int(statement, 4);

  if (status == 0 || del > 0){
    int rc = unlink(filename);
    if (rc == 0)
      // Now delete the current row
    else 
      // unlink failed, find out why, try again or ... ?
  } 

  rc = sqlite3_step(statement);
}
sqlite3_finalize(statement);
sqlite3_exec(db, "COMMIT", 0, 0, 0);

我可以调用单个sql语句删除符合条件的所有行,但如果由于某种原因unlink失败,我不想这样做。

我可以调用删除当前行的操作吗?

编辑: 所以有一个名为rowid的特殊列。我只是将其添加为 先前的语句并创建另一个语句,如“从表中删除rowid =?”并传入当前的rowid?

这应该正常吗?这是最好的解决方法吗?

2 个答案:

答案 0 :(得分:3)

就效率而言,它可能不是最有效的。如果您在数千或更多行的级别上执行此操作,则应考虑执行以下操作之一(或组合):

  • 将您的查询更改为仅考虑del为>的行0(SELECT id,status,filename,del FROM mytable WHERE del > 0)。您正在使用当前方法执行表扫描,您应该始终尽量避免。还要确保在del列上有索引。

  • 构建行ID的中间数组,然后执行以下格式的查询:DELETE FROM table WHERE id IN (?),参数化值是您收集的行ID,它们连接成逗号分隔的字符串。根据您正在处理的行数,您可以将此删除设置为批量执行(批量大小为1000,5000等);因为它是SQLite,所以调到你正在运行的设备。

  • 使用以下格式在连接创建时注册自定义SQLite函数:

    void deleteFileFunc(sqlite3_context * context, int argc, sqlite3_value ** argv) {
      assert(argc == 1);
      const char * fileName = sqlite3_value_text(argv[0]);
      int rc = unlink(fileName);
      sqlite3_result_int(context, rc);
    }
    sqlite3_create_function(db, "delete_file", 1, SQLITE3_UTF8, NULL, &deleteFileFunc, NULL, NULL);
    

然后将数据库查询更改为DELETE FROM mytable WHERE del > 0 AND delete_file(filename) == 0形式。只有删除成功时才会删除该行,并且您不需要迭代结果集。 SQLite 3创建功能页面:http://www.sqlite.org/c3ref/create_function.html

答案 1 :(得分:0)

直接删除行就可以了。

文档说它不会干扰正在运行的 SELECT 删除已读取的行。

但如果删除预期稍后读取的未来行,则结果未定义。

https://www.sqlite.org/isolation.html