【问题标题】:Android Sqlite INSERT error when table contains only _id表仅包含_id时Android Sqlite INSERT错误
【发布时间】:2012-07-18 06:17:47
【问题描述】:

我有一个只包含 _id 的 SQLite 表:

"create table rule (_id integer primary key);";

运行这组命令时:

ContentValues initialValues = new ContentValues();
mDb.insert(TABLE, null, initialValues)

我得到以下异常:

android.database.sqlite.SQLiteException: near "null": syntax error (code 1): , while compiling: INSERT INTO rule(null) VALUES (NULL)

发生初始错误是因为 ContentValues 不能为空。 Android 提供了一个名为 nullColumnHack 的便利参数,它允许您传递值为 null 的单个列,以绕过此问题。

但这不适用于我的情况,因为行 ID (_id) 不能为空!根据SQLite language docs 中的语法,我希望能够运行 SQLite 代码:

INSERT INTO rule DEFAULT VALUES;  

如何使用 android insert 方法实现这样的效果?或者我需要在我的 create 语句中添加什么内容?

更新:在表仅包含 rowid 的情况下,正确的语法是使用 INSERT INTO __DEFAULT VALUES。

android 中列出的 sqlite 插入方法不支持将 DEFAULT VALUES 作为选项。

A bug has been filed with google 并获得对默认值的支持,需要执行以下命令:

mDb.execSQL("INSERT INTO rule DEFAULT VALUES;");
Cursor c = mDb.rawQuery("SELECT last_insert_rowid()",null);
c.moveToFirst();
int rowid = c.getInt(0);

正如接受的答案中所述,我们可以通过使用 nullHackColumn 并将行 ID (_id) 分配给 null 并让 SQLite 从 null 转换为自动递增值来解决此问题(和默认值)。

【问题讨论】:

    标签: android sqlite


    【解决方案1】:

    正如 jeet 所提到的,您可以提供 nullColumnHack 作为第二个参数。正如您自己提到的那样,autoincrement 不需要增加主键的值。 所以语法:

    insert into rule (_id) values(null)
    

    其中 _id 是主键,自动增量值对于 sql 是正确的。我认为大多数 SQL 数据库都会用新的增量值替换null,至少 MySQL、SQLite 和 Oracle 可以做到这一点

    因此:

    ContentValues cv = new ContentValues();
    db.insert("rule", "_id", cv);
    

    应该会给你想要的结果。

    【讨论】:

    • 您在“插入规则(_id)值(null)”是有效的SQL语法的语句中是正确的。但是,这是我在发布问题之前尝试的第一次尝试,因为 SQLite 会抛出错误,因为它不会按照您的建议将值与自动增量中的下一个值交换。相反,SQLite 实际上会尝试为 _id 分配值 NULL。
    • 刚刚检查过。我可以使用提供的代码插入具有自动递增值的行。它确实会尝试在 _id 上分配 NULL 值,但后者会导致自动增量,因为它是主键。你在这方面遇到了什么问题?
    • 你是对的!当我最初尝试这个时,我将 cv 作为 null 传递,我相信这导致了问题。这是正确的语法,谢谢!
    【解决方案2】:

    您需要将autoincrement 添加到您的创建表查询中,例如:

    "create table rule (_id integer primary key autoincrement);";
    

    在您的情况下,您需要在每次插入时手动设置行的 ID。这样,当您插入空行时,它会自动递增,就像您在案例中所做的那样。

    【讨论】:

    • 其实不用特意写AUTO_INCREMENT。您只需将主键定义为 _id INTEGER PRIMARY KEY。
    • 好的,但是在你的 contentvalues 中没有添加行的 id,所以我假设它应该自动递增。此外,我没有看到在这种情况下不应自动递增的原因。为什么要实现自己的设置 id 的逻辑,而不是让数据库来处理。我不会将 id 设置为自动增量的唯一原因是,如果我从服务中获取数据并且我想要该结构的普通副本。
    • ContentValues 无法设置行的 id,只是因为它不知道 id 是什么,没有先查询数据库并创建我自己的可怜的自动增量。我不想走这条路。 SQLite 语法中不需要自动增量(请参阅sqlite.org/faq.html#q1)。自动增量将使用原始问题中提供的创建表语法,但问题是 android 的 INSERT 方法不支持默认值。
    【解决方案3】:

    试试这个方法:

    ContentValues initialValues= new ContentValues();
    if(check here --id is null----)
    {
      initialValues.put("_id", "0");  
    }
    else
    {
      initialValues.put("_id", id);  
    }
    
    mDb.insert(TABLE, null, initialValues)
    

    【讨论】:

    • 不,E/SQLiteLog(936): (20) 语句在 6 处中止:[INSERT INTO rule(_id) VALUES (?)] 数据类型不匹配
    • 因为 id 是主键,所以它不能为空。你能继续为空值插入 0 吗??
    • 对,id是主键,不能为空。但是,按照同样的逻辑,我不能只插入 0 作为值,因为这仅适用于第一条规则,当我需要创建第二条规则时,我必须将下一行设为 1 并基本上创建我自己的自动增量。 . 0 会很糟糕,因为数据库是 1-indexed 而不是 0-indexed。
    【解决方案4】:

    检查以下内容:

    http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert(java.lang.String, java.lang.String, android.content.ContentValues)

    SQL 不允许插入一个完全空的行而不命名至少一个列名。如果您提供的值为空,则表示不知道列名并且无法插入空行。如果未设置为 null,则 nullColumnHack 参数提供可为空的列名的名称,以便在您的值为空的情况下显式插入 NULL。

    【讨论】:

    • 是的,我看到了,但是如果我们将 nullColumnHack 设置为 _id(行 id),那么查询将失败,因为生成的 SQL 是: INSERT INTO rule(_id) values NULL;显然,这种语法是不正确的,因为我们不想为 _id 提供值,而是希望生成该值。
    • 但是为什么你需要一个只有列 id 的表。它可以解决什么目的。
    • 规则是更大数据库的一部分。 Rule 将包含多种Rules 的ID,并用作many_to_many 表“filter_rules”的外键。RuleA 和RuleB 的主键(rule_ptr)是Rule 表的外键。这用于防止多个many_to_many表(即filter_ruleA,filter_ruleB)
    【解决方案5】:

    插入需要一个空值,您只需输入

    db.insert ("people", null, c);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多