我正在开发使用flutter
和sqflite
软件包学习外语的移动应用程序。该应用程序具有sqlite
数据库,其中包含单词表和某种类型的集合(多对多关系)。此数据存储在应用程序资产中,并在安装应用程序时像在sqflite指南https://github.com/tekartik/sqflite/blob/master/sqflite/doc/opening_asset_db.md中一样加载到移动数据库目录中
用户可以添加自己的单词和集合,也可以添加或更改我的单词。我曾经认为我可以使用sqlite upsert
来实现,但是如果用户添加的单词与我在应用程序更新中添加的单词相同,则会出现冲突。如果我执行upsert
,则该单词不会出现在我的单词集中,因为它们受id约束;否则,如果我执行replace
,则单词将从用户的集合中消失。
我认为我需要在sqlite insert or replace
中进行某种级联ID更新,但是没有这种功能。
有什么想法吗?
答案 0 :(得分:0)
我认为我需要在sqlite插入或 替换,但没有这种功能。
有这样的功能;您可以将ON UPDATE CASCADE
指定为FOREIGN KEY定义/条款的一部分。您还可以编码ON DELETE CASCADE
SQLite Foreign Key Support - 4.3. ON DELETE and ON UPDATE Actions。
由于这被编码为子表的一部分,因此您不能使用ALTER TABLE COLUMN更改列的属性(除了重命名列之外)。您将必须:-
INSERT INTO replacement_table_with_original_name SELECT * FROM renamed_table
(显然更改了 replacement_table_with_original_name 和 renamed_table )为实际名称。例如,考虑您的场景的以下表示形式(从可用信息中),然后将在保留现有数据的同时添加ON UPDATE CASCADE
和ON DELETE CASCADE
,它还会删除没有冲突的行并进行更新没有冲突或损失的参考值:-
-- Create the original tables and load some test data
CREATE TABLE IF NOT EXISTS word_table (id INTEGER PRIMARY KEY, other_column TEXT);
INSERT INTO word_table VALUES (null,'WA'),(null,'WB'),(null,'WC');
CREATE TABLE IF NOT EXISTS collection_table (id INTEGER PRIMARY KEY, other_column TEXT);
INSERT INTO collection_table VALUES (null,'CA'),(null,'CB'),(null,'CC');
CREATE TABLE IF NOT EXISTS word_collection_map (
word_reference INTEGER NOT NULL REFERENCES word_table(id),
collection_reference INTEGER NOT NULL REFERENCES collection_table(id),
PRIMARY KEY (word_reference,collection_reference) ) WITHOUT ROWID;
INSERT INTO word_collection_map VALUES(1,1),(3,2),(3,3),(2,1),(2,2),(2,3);
-- show the result
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
;
-- ADDING CASCADE
ALTER TABLE word_collection_map RENAME TO old_word_collection_map;
CREATE TABLE IF NOT EXISTS word_collection_map (
word_reference INTEGER NOT NULL REFERENCES word_table(id) ON UPDATE CASCADE ON DELETE CASCADE ,
collection_reference INTEGER NOT NULL REFERENCES collection_table(id) ON UPDATE CASCADE ON DELETE CASCADE,
PRIMARY KEY (word_reference,collection_reference) ) WITHOUT ROWID;
INSERT INTO word_collection_map SELECT * FROM old_word_collection_map;
DROP TABLE IF EXISTS old_word_collection_map;
-- Show results (should match first)
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
;
-- DELETE a word no conflicts
DELETE FROM word_table WHERE other_column = 'WC';
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
;
-- UPDATE the FK parent no conflicts
UPDATE collection_table SET id = 10 WHERE id = 3;
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
;
-- Create the original tables and load some test data
CREATE TABLE IF NOT EXISTS word_table (id INTEGER PRIMARY KEY, other_column TEXT)
> OK
> Time: 0.118s
INSERT INTO word_table VALUES (null,'WA'),(null,'WB'),(null,'WC')
> Affected rows: 3
> Time: 0.104s
CREATE TABLE IF NOT EXISTS collection_table (id INTEGER PRIMARY KEY, other_column TEXT)
> OK
> Time: 0.097s
INSERT INTO collection_table VALUES (null,'CA'),(null,'CB'),(null,'CC')
> Affected rows: 3
> Time: 0.094s
CREATE TABLE IF NOT EXISTS word_collection_map (
word_reference INTEGER NOT NULL REFERENCES word_table(id),
collection_reference INTEGER NOT NULL REFERENCES collection_table(id),
PRIMARY KEY (word_reference,collection_reference) ) WITHOUT ROWID
> OK
> Time: 0.097s
INSERT INTO word_collection_map VALUES(1,1),(3,2),(3,3),(2,1),(2,2),(2,3)
> Affected rows: 6
> Time: 0.105s
-- show the result
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
> OK
> Time: 0.001s
-- ADDING CASCADE
ALTER TABLE word_collection_map RENAME TO old_word_collection_map
> OK
> Time: 0.108s
CREATE TABLE IF NOT EXISTS word_collection_map (
word_reference INTEGER NOT NULL REFERENCES word_table(id) ON UPDATE CASCADE ON DELETE CASCADE ,
collection_reference INTEGER NOT NULL REFERENCES collection_table(id) ON UPDATE CASCADE ON DELETE CASCADE,
PRIMARY KEY (word_reference,collection_reference) ) WITHOUT ROWID
> OK
> Time: 0.096s
INSERT INTO word_collection_map SELECT * FROM old_word_collection_map
> Affected rows: 6
> Time: 0.094s
DROP TABLE IF EXISTS old_word_collection_map
> OK
> Time: 0.081s
-- Show results (should match first)
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
> OK
> Time: 0s
-- DELETE a word no conflicts
DELETE FROM word_table WHERE other_column = 'WC'
> Affected rows: 1
> Time: 0.086s
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
> OK
> Time: 0.001s
-- UPDATE the FK parent no conflicts
UPDATE collection_table SET id = 10 WHERE id = 3
> Affected rows: 1
> Time: 0.089s
SELECT word_table.other_column, collection_table.other_column
FROM word_collection_map
JOIN word_table ON word_table.id = word_reference
JOIN collection_table ON collection_table.id = collection_reference
> OK
> Time: 0s