【问题标题】:NOT NULL constraint failed while copying data to a new table将数据复制到新表时,NOT NULL 约束失败
【发布时间】:2019-01-09 23:57:52
【问题描述】:

我将我的数据库从 SQLiteOpenHelper 迁移到 Room。

我有一张表要更改,我们称之为"my_table"。 其简化的创建语句:

CREATE TABLE `my_table`
 (`_id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `title` TEXT
 )

在升级期间,我添加了新列 type INTEGER NOT NULL(我还添加了外键并进行了其他重大更改,这就是创建新表而不是更改现有表的原因):

CREATE TABLE "new_table" 
 (`_id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `title` TEXT,
  `type` INTEGER NOT NULL
 )

然后我想将数据从my_table 复制到new_table 并设置type 列的值。

SQL 语句:

INSERT INTO new_table (title) 
SELECT title FROM my_table;
UPDATE new_table SET type = 1;
DROP TABLE my_table;
ALTER TABLE new_table RENAME TO my_table;

Android 迁移:

public static final Migration MIGRATION_TEST = new Migration(1, 2) {
    @Override
    public void migrate(@NonNull SupportSQLiteDatabase database) {
        // Create new table
        database.execSQL("CREATE TABLE new_table (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `type` INTEGER NOT NULL)");
        // Copy some data
        database.execSQL("INSERT INTO new_table (title) SELECT title FROM old_table"); // constraint violation
        // Insert default value into the measures column
        database.execSQL("UPDATE new_table SET type = 1");
        // Delete old table
        database.execSQL("DROP TABLE old_table");
        // Rename new table
        database.execSQL("ALTER TABLE new_table RENAME TO my_table");
    }
};

显然我得到NOT NULL constraint failed: new_table.type 错误:

android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: new_table.type (code 1299)
Error Code : 1299 (SQLITE_CONSTRAINT_NOTNULL)
Caused By : Abort due to constraint violation.
(NOT NULL constraint failed: new_table.type (code 1299))

我可以通过更改新表的创建语句并为type 列设置默认值来避免它。

CREATE TABLE "new_table" 
 (`_id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `title` TEXT,
  `type` INTEGER NOT NULL DEFAULT 1
 )

但我不想这样做,因为 Room 不支持开箱即用的默认值,并且为了避免将来在向表中插入新值时出现错误。

在将数据插入新表时,是否有任何解决方法可以避免此错误?

【问题讨论】:

    标签: android sql sqlite android-room


    【解决方案1】:

    我认为以下方法可能有效:-

    database.execSQL("INSERT INTO new_table (title,type) SELECT title, 1 FROM old_table");
    

    也就是说,您现在要根据 SELECT 语句插入 2 列。 SELECT 返回 2 个值,即 old_table 中的标题和字面值 1。

    你就不需要database.execSQL("UPDATE new_table SET type = 1")

    【讨论】:

    • 行得通!谢谢你。我在INSERT 语句的示例中没有看到这一点(或者可能没有注意到)。您能否提供解释此行为的链接?
    • 基本上SELECT ......就是一个表达式列表 简单的SELECT语句返回的行的列数等于结果表达式列表后面的表达式个数替换和别名。表达式。每个结果行是通过计算结果表达式列表中的表达式来计算的
    • 非常感谢 Mike 的回答和解释!
    猜你喜欢
    • 2019-01-21
    • 2015-04-22
    • 2018-08-24
    • 2022-01-19
    • 2021-11-16
    • 2020-12-18
    • 2021-03-20
    • 2020-02-11
    • 2019-02-13
    相关资源
    最近更新 更多