使用查询字符串在Android SQLiteDatabase中执行插入/更新/删除的正确方法是什么?

我一直在查看官方文档( http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html )以及与StackOverflowpost和实际观察到的行为的交叉引用,文档似乎是在几个方面误导并可能是错误的。

我正在尝试执行参数化查询以插入/更新/删除,就像使用rawQuery(String sql, String[] arguments). 我需要通过查询而不是在SQLiteDatabase类上使用insert / update / delete方法来执行此操作,因为在许多情况下,查询跨越多个表,并且在任何情况下我们都编写了一组我们用于此app的查询在我们所有的平台上(也为SQLite编写),最好按原样使用它。

这是我发现令人困惑/误导的内容:

  • doc对rawQuery说,语句不能用分号终止,但它实际上似乎没有任何区别。 这对我很重要,因为我们有一个巨大的XML文档,里面填充了我在我的应用程序中跨多个平台使用的查询,如果可能的话,我更愿意保持相同。

  • rawQuery似乎不适用于插入(是的,我尝试过使用和不使用分号)。 该文件没有说明这一点。 我确实看到它返回一个Cursor,我想这可能是一个倾斜提示,它只适用于select,但不一定 – 它可以简单地返回零长度或null Cursor,当它们没有结果集时。

  • execSQL(String sql, Object[] bindArgs)明确表示它不适用于插入,但事实上确实如此!

  • 此外,尽管execSQL(String, Object[])明确告诉您不要尝试CRUD操作,但它的无参数版本不包含此类警告,并且也可以正常工作(缺点是不允许SQL参数)。

所有这一切的结果是我能够找到成功执行带参数化参数的插入的唯一方法是使用文档明确指示您不要用于此目的的一种工作方法。

此外,对于插入/更新/删除而言,rawQuery不起作用真是一个让人失望,因为我们有一个通用的数据层,如果我们可以使用单个统一的API调用来运行我们所有的CRUD查询,它会更优雅。数据库。

那么这里发生了什么? 这份文件是否已经过时了? 是否可以使用execSql进行插入,更新等? 有没有人成功使用rawQuery进行插入?


附录:

针对OS运行:Android 4.3。

示例查询(什么工作,什么不工作)

 // Works db.execSql("INSERT into MyTable (Col1, Col2) VALUES (?, ?)", new String[] { "Foo", "Bar" }); db.execSql("INSERT into MyTable (Col1, Col2) VALUES (?, ?);", new String[] { "Foo", "Bar" }); // No exception thrown, but no changes made to the database db.rawQuery("INSERT into MyTable (Col1, Col2) VALUES (?, ?)", new String[] { "Foo", "Bar" }); db.rawQuery("INSERT into MyTable (Col1, Col2) VALUES (?, ?);", new String[] { "Foo", "Bar" }); 

你是对的。 文档令人困惑。 总的来说,该设计试图围绕sqlite3 C API提供方便的Java包装器。 在大多数情况下,如果按照设计者的意图使用它,它可以正常工作,例如使用CRUD操作的便捷方法。 但是他们还需要提供原始查询方法execSQL()rawQuery()以用于方便的CRUD方法不够强大或根本不适用的情况( CREATE TABLE等)。 这会导致泄漏抽象。

doc对rawQuery说,语句不能用分号终止,但它实际上似乎没有任何区别。 这对我很重要,因为我们有一个巨大的XML文档,里面填充了我在我的应用程序中跨多个平台使用的查询,如果可能的话,我更愿意保持相同。

文档很糟糕。 事实上,Android SQLiteDatabase本身使用以分号结尾的查询字符串调用rawQuery

rawQuery似乎不适用于插入(是的,我尝试过使用和不使用分号)。 该文件没有说明这一点。 我确实看到它返回一个Cursor,我想这可能是一个倾斜提示,它只适用于select,但不一定 – 它可以简单地返回零长度或null Cursor,当它们没有结果集时。

确实有效,但您需要了解它在原生级别上的工作原理。

execSQL()视为sqlite3_exec() ,它运行查询并返回成功或错误代码。

rawQuery()视为sqlite3_prepare() ,它编译查询但尚未运行它。 要实际运行它,请使用Cursor上的moveTo...()方法之一。 可以将其视为sqlite3_step() 。 将任何rawQuery()moveTo...()将实际改变数据库。

execSQL(String sql, Object[] bindArgs)明确表示它不适用于选择,但事实上确实如此!

此外,尽管execSQL(String, Object[])明确告诉您不要尝试CRUD操作,但它的无参数版本不包含此类警告,并且也可以正常工作(缺点是不允许SQL参数)。

它适用于所有CRUD操作。 对于CRUD的R读取部分,没有办法获得所选数据。

你想要的是execSQL()用于插入。 或者你可以这样做:

 ContentValues values = new ContentValues(); values.put ("col1", "foo"); values.put ("cols2", "bar"); getDb().insertOrThrow ("MyTable", null, values); 

对于查询,您可以使用rawQuery。