【问题标题】:Copying an SQLite Table Applying Default Values应用默认值复制 SQLite 表
【发布时间】:2019-10-08 10:27:54
【问题描述】:

我的 Android 应用中有一个 SQLite 数据库,我想更新它。更新需要将数据类型从 INT 更改为 FLOAT。我理解在 SQLite 中实现这一点的方法是创建一个新表,复制数据,然后用新表替换旧表。复制如下:

INSERT INTO newTable SELECT * FROM oldTable

整数值可以方便地转换为浮点值。

现在,另一个问题是,以前的可选列现在是“NOT NULL”,但有一个默认值。作为上述过程的一部分,我希望使用以下语句将所有 NULL 实例替换为默认值:

INSERT INTO newTable SELECT * FROM oldTable ON CONFLICT REPLACE

或者,为了完整起见,在 Android/Kotlin 中:

db.execSQL(“INSERT INTO newTable SELECT * FROM oldTable ON CONFLICT REPLACE”)

这给了我一个语法错误,我在别处找不到合适的例子。实现这一点的正确语法是什么 - 我正在尝试做的甚至可能吗?

【问题讨论】:

    标签: android sqlite sql-insert


    【解决方案1】:

    如果您查看the documentation for INSERT,您会发现它应该是INSERT OR REPLACE ...,而且,是的,它将非空列中的空值替换为默认值。

    Replace conflict resolution documentation:

    当 UNIQUE 或 PRIMARY KEY 约束违规发生时,REPLACE 算法会在插入或更新当前行之前删除导致约束违规的预先存在的行,并且命令会继续正常执行。 如果发生 NOT NULL 约束违规,则 REPLACE 冲突解决方案将 NULL 值替换为该列的默认值,或者如果该列没有默认值,则使用 ABORT 算法。如果发生 CHECK 约束或外键约束违规,则 REPLACE 冲突解决算法的工作方式类似于 ABORT。


    例子:

    sqlite> CREATE TABLE foo(x, y NOT NULL DEFAULT 1);
    sqlite> INSERT INTO foo(x,y) VALUES ('a', null);
    Error: NOT NULL constraint failed: foo.y
    sqlite> INSERT OR REPLACE INTO foo(x,y) VALUES ('a', null);
    sqlite> SELECT * FROM foo;
    x           y         
    ----------  ----------
    a           1         
    

    【讨论】:

    • 谢谢。表格副本确实以这种方式工作。但是有一个副作用:其他未定义默认值的非空列会导致此语句失败。我想知道这是否可以避免。当没有有意义的默认值时,不指定它实际上有助于发现编程错误。
    • @jerry 您不能在非空列中存储空值。如果没有使用默认值,它当然会失败。它还应该做什么?
    • 是的,但奇怪的是,当尝试将非空值从源表复制到目标表的同一列时,它会引发空错误。非空列不一定需要默认值。我的表中有几个这样的列没有有意义的默认值,不指定它实际上可以帮助发现逻辑错误。现在,如果程序未能设置该值,则默认使用可能错误的默认值。
    • 再玩一玩,结果发现语句INSERT OR REPLACE INTO newTable SELECT * FROM oldTable 具有所描述的副作用,而INSERT OR REPLACE INTO newTable(Col1, Col2, ...) SELECT Col1, Col2, ... 复制其他非空列没有问题。我没有洞察力来解释这一点,所以我不会将其发布为答案。这可能代价高昂。但随着@Shawn 的回答,它解决了我的问题。
    猜你喜欢
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    相关资源
    最近更新 更多