Sqlite 错误:没有这样的表 main.table_name 存在

Sha*_*ita 4 c# sqlite uwp

在我的 UWP 应用中,我在 sqlite db 中的 App Start 上创建表。此外,我编写了各种 Alter 命令,其中我检查已安装的应用程序是否包含 Customertbl 中的相应列,并将 Customertbl 表重命名为 Customertbl_old 并创建新表 Customertbl,最后将 Customertbl_old 表中的所有行存储到 Customertbl 表中。然后我删除表 Customertbl_old。现在,到这部分一切正常,但是,当我尝试在 OwnerTbl 中删除/插入一行时,它会抛出一个异常说

Sqlite 错误:没有这样的表 main.Customertbl_old 存在。

//**Code where a column name is updated by creating new table**
string tableCommand = "PRAGMA table_info(Recordings)"; 
SqliteCommand createTable = new SqliteCommand(tableCommand, db);
SqliteDataReader query = createTable.ExecuteReader(); 
tableCommand = "PRAGMA foreign_keys = off; " + " 
BEGIN TRANSACTION; " +
" ALTER TABLE Customertbl RENAME TO _Customertbl_old; " +
" CREATE TABLE Customertbl ( " + " ID INTEGER PRIMARY KEY AUTOINCREMENT, " + " CustomerName NVARCHAR(100) NULL, " + " Password NVARCHAR(100) NULL, " + " 
pkID INTEGER NULL, " + " ActivityName NVARCHAR(255) NULL);" +
 " INSERT INTO Customertbl(Name,Password) " + " SELECT Name,Password " + " 
FROM _Customertbl_old ;" + " COMMIT; " + " PRAGMA foreign_keys=on; " + " 
DROP TABLE 
_Customertbl_old";

// **code where exception occur**
using (SqliteConnection db = new 
SqliteConnection("Filename=" + App.dbName)) 
{ 
db.Open(); 
SqliteCommand deleteCommand = new SqliteCommand(); 
try 
{ 
    deleteCommand.Connection = db; 
    deleteCommand.CommandText = "DELETE FROM Ownertbl where fkId = @id";  
    deleteCommand.Parameters.AddWithValue("@id", id);  
    deleteCommand.ExecuteReader()//here the exception occur ;  
    db.Close(); 
 } 
}
Run Code Online (Sandbox Code Playgroud)

Tri*_*und 9

TL; 博士

如果ALTER TABLE...由于将 SQLite 升级到版本 3.26 或更高版本而导致以前工作的 使用中断,则PRAGMA legacy_alter_table=ON在进行这些更改之前使用“快速修复” 。但是,重新组织命令可能会更好(请参阅“安全方法)。如果您使用 3.26 后版本的 SQLite 开始一个新项目,我绝对会建议您使用“安全方式”并避免使用PRAGMA.

发生了什么

由于ALTER TABLE3.25.0 (2018-09-15) 和3.26.0 (2018-12-01)版本中对 SQLite 的命令进行了更改,因此出现了您的问题。有关官方文档,请参阅SQLite 网站上的ALTER TABLE

在此之前的版本,(例如来自重命名表MY_TABLEA_BETTER_NAMED_TABLE改变了表的名称。对该表的任何引用(即在外键 (FK) 约束或触发器中)都没有重命名。如果目标只是重命名表,这可以合理地被视为一个错误,因为没有(简单的、正式的)方法来更改这些引用,并且会留下不一致的数据库。

上述更改通过将对表名称的更改传播到任何此类引用中来“修复”此问题。因此,您可以重命名 FK 约束或触发器引用的表,并保留一致的数据库。

当它引起问题时

OP 的问题出现 - 间接 - 由于命令的能力非常有限(与非 Lite 数据库引擎相比)ALTER TABLE。在 SQLite 中,它所能做的就是更改表名、列名或添加新列(到行的“结尾”)。如果您需要对表做任何比这更复杂的事情,您必须“有创意”(本质上,创建一个新的替换表并从旧表中填充它)。但是,有两种方法可以做到这一点,其中一种方法被上述更改“试图变得更有帮助” “打破”。

安全的方式

  • MY_TABLE_NEW使用您需要的所有新属性创建一个新的(例如)。

  • 将现有数据从 迁移MY_TABLEMY_TABLE_NEW(根据需要添加默认值/缺失值)。

  • 删除原表MY_TABLE。此时,引用的任何 FK 约束和触发器MY_TABLE都将失败,但这并不重要。

  • 用于ALTER TABLE MY_TABLE_NEW RENAME TO MY_TABLE将格式正确的新表的名称更改回原始表的名称。现在将再次满足任何 FK 约束/触发器引用(假设它们不是针对已删除的列!)

以上将在更改前后都有效。在更改之前,不注意 FK 约束/触发器;更改后,将没有引用,MY_TABLE_NEW因此不会传播任何内容。

破碎的道路

在更改之前,以下过程同样有效:

  • 使用ALTER TABLE MY_TABLE RENAME TO MY_TABLE_OLD. 此时,在旧版本中,任何 FK 约束/触发器都会不一致,但这并不重要。

  • 使用您需要的所有新属性创建一个替换MY_TABLE。现在将满足任何参考。

  • 将现有数据从 迁移MY_TABLE_OLDMY_TABLE(根据需要添加默认值/缺失值)。

  • 删除原始(但重命名)表MY_TABLE_OLD

新版本会出现问题,因为它将重命名对原始表 ( MY_TABLE) 的所有引用,以便它们现在引用即将删除的表 ( MY_TABLE_OLD)。其他任何步骤都不会影响这些引用,因此您会得到一个不一致的数据库(对不存在的 的引用MY_TABLE_OLD)。

修复

将表操作步骤的顺序更改为The Safe Way 中的顺序,或者 - 如ALTER TABLE页面上所述- 在命令PRAGMA legacy_alter_table=ON之前发出ALTER TABLE命令。这将防止“改进”行为将引用重命名MY_TABLEMY_TABLE_OLD.