【问题标题】:SQLite replace a row in one database from a row in another databaseSQLite 从另一个数据库中的一行替换一个数据库中的一行
【发布时间】:2021-10-12 03:32:25
【问题描述】:

我有两个数据库文件,每个文件都有一个共同的单表结构。当第二个数据库中的列设置了标志时,我想用第二个数据库中的类似行替换第一个数据库中的整个表行。我知道如何将一个数据库附加到另一个数据库,但我无法找出正确的 UPDATE SET 指令。我正在寻找字符串指令以传递基于 kotlin 的 android studio android.database.sqlite execSQL 调用。

例如: 每个数据库中的表有五列名为 - name,address,date,value,flag 我打开主数据库 (main.db) 并调用 ATTACH DATABASE 将辅助数据库 (secondary.db) 附加为“db2” 然后,我想在主数据库中找到与辅助数据库中名称和地址字段匹配且辅助数据库中的标志字段包含值 1 的行匹配的行。
然后我想用辅助数据库中的行替换主数据库行

我为 execSQL 尝试了以下字符串命令的变体,但未成功:

val TABLE_NAME = "users"

val COL_NAME = "name"

val COL_ADR = "address"

val COL_DATE = "date"
    
val COL_VAL = "value"
    
val COL_FLG = "flag"

val db = this.writableDatabase

val attachDb = ("ATTACH DATABASE '$secondaryDbFile' AS 'db2'")            
db.execSQL(attachDb) 

val updateRows = ("UPDATE $TABLE_NAME SET ($COL_NAME, $COL_ADR, $COL_DATE, $COL_VAL, $COL_FLG) FROM db2.$TABLE_NAME WHERE $COL_FLG = 1")
db.execSQL(updateRows) 

我对 SQLite 的掌握不够好,无法构建正确的指令,请帮助。

【问题讨论】:

    标签: android sqlite kotlin android-sqlite


    【解决方案1】:

    您在UPDATE 语句中使用的语法是错误的。
    您可以使用 ROW VALUES 并仅更新 datevalueflag 列,因为其他 2 列必须匹配。
    还要为 2 个表使用别名(如 t1t2)来区分具有相同名称的列:

    val db = this.writableDatabase
    val attachDb = ("ATTACH DATABASE '$secondaryDbFile' AS db2") // no need for single quotes around db2
    db.execSQL(attachDb)
    val updateRows = "UPDATE $TABLE_NAME AS t1 " + 
                     "SET ($COL_DATE, $COL_VAL, $COL_FLG) = " +
                     "(SELECT t2.$COL_DATE, t2.$COL_VAL, 1 FROM db2.$TABLE_NAME AS t2 WHERE (t2.$COL_NAME, t2.$COL_ADR) = (t1.$COL_NAME, t1.$COL_ADR) AND t2.$COL_FLG = 1) " +
                     "WHERE EXISTS (SELECT 1 FROM db2.$TABLE_NAME AS t2 WHERE (t2.$COL_NAME, t2.$COL_ADR) = (t1.$COL_NAME, t1.$COL_ADR) AND t2.$COL_FLG = 1);"
    db.execSQL(updateRows)
    

    对于不允许更新表使用别名的 SQLite 版本,请使用以下语句:

    val updateRows = "UPDATE $TABLE_NAME " + 
                     "SET ($COL_DATE, $COL_VAL, $COL_FLG) = " +
                     "(SELECT t2.$COL_DATE, t2.$COL_VAL, 1 FROM db2.$TABLE_NAME AS t2 WHERE (t2.$COL_NAME, t2.$COL_ADR) = ($TABLE_NAME.$COL_NAME, $TABLE_NAME.$COL_ADR) AND t2.$COL_FLG = 1) " +
                     "WHERE EXISTS (SELECT 1 FROM db2.$TABLE_NAME AS t2 WHERE (t2.$COL_NAME, t2.$COL_ADR) = ($TABLE_NAME.$COL_NAME, $TABLE_NAME.$COL_ADR) AND t2.$COL_FLG = 1);"
    

    如果 SQLite 的版本为 3.33.0+,UPDATE 语句的语法可以被简化,但它不适用于 Android,到目前为止,API 级别 31 支持版本 3.32.2。

    这是UPDATE 声明的简化版本(供未来的读者使用):

    val updateRows = "UPDATE $TABLE_NAME AS t1 " + 
                     "SET ($COL_DATE, $COL_VAL, $COL_FLG) = (t2.$COL_DATE, t2.$COL_VAL, 1) " +
                     "FROM db2.$TABLE_NAME AS t2 WHERE (t2.$COL_NAME, t2.$COL_ADR) = (t1.$COL_NAME, t1.$COL_ADR) AND t2.$COL_FLG = 1;"
    

    【讨论】:

    • 非常感谢forpas,正是我需要的!
    • 虽然该语句适用于运行 API 30 (sqlite V3.28) 的设备,但不适用于 API 29 (sqlite V3.22)。在 Api 29 上,我收到以下错误:android.database.sqlite.SQLiteException:靠近“AS”:语法错误。有没有办法使用别名来解决这个错误?
    • @TFont 我添加了另一个版本的查询,没有更新表的别名。
    • 再次感谢 forpas,没有别名的查询在两个 API 中都能正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-12
    相关资源
    最近更新 更多