简体   繁体   English

如何在不丢失外键的情况下合并两个sqlite数据库?

[英]How to merge two sqlite databases without losing foreign keys?

I'm developing mobile app for learning a foreign language using flutter and sqflite package. 我正在开发用于使用fluttersqflite软件包学习外语的移动应用程序。 The app has sqlite database with tables for words and some kind of collections (relation many to many). 该应用程序具有sqlite数据库,其中包含单词表和某种类型的集合(多对多关系)。 This data is stored in the app asset and is loads to mobile database directory when the app is installing like in sqflite guide https://github.com/tekartik/sqflite/blob/master/sqflite/doc/opening_asset_db.md 此数据存储在应用程序资产中,并在安装应用程序时像在sqflite指南https://github.com/tekartik/sqflite/blob/master/sqflite/doc/opening_asset_db.md中一样加载到移动数据库目录中
User can add own words and collections as well as I wanna be able to populate or change mine. 用户可以添加自己的单词和集合,也可以添加或更改我的单词。 I used to think that I can achieve that with sqlite upsert but in case that user added the same word as I did in app's update, there is appears a conflict. 我曾经以为我可以使用sqlite upsert实现此目的,但是如果用户添加的单词与我在应用程序更新中添加的单词相同,则会出现冲突。 If I do upsert then this word doesn't appear in my word collections because they are bound by id, otherwise, if I do replace , then word disappear from user's collections. 如果我进行upsert则该单词不会出现在我的单词集中,因为它们受id约束;否则,如果我执行replace ,则单词将从用户的集合中消失。

I think I need some kind of cascade id update in sqlite insert or replace , but there is no such feature. 我想我需要在sqlite insert or replace某种级联ID更新,但是没有这种功能。

Any ideas, please? 有什么想法吗?

I think I need some kind of cascade id update in sqlite insert or replace, but there is no such feature. 我认为我需要在sqlite插入或替换中进行某种级联ID更新,但是没有这种功能。

There is such a feature; 有这样的功能; you specify ON UPDATE CASCADE as part of the FOREIGN KEY definition/clause. 您可以将ON UPDATE CASCADE指定为FOREIGN KEY定义/条款的一部分。 You can also code ON DELETE CASCADE SQLite Foreign Key Support - 4.3. 您还可以编码ON DELETE CASCADE SQLite外键支持-4.3。 ON DELETE and ON UPDATE Actions . ON DELETE和ON UPDATE操作

As this is coded as part of the child table and that you cannot use ALTER TABLE COLUMN to change the column's attributes (other than to RENAME a column). 由于这被编码为子表的一部分,因此您不能使用ALTER TABLE COLUMN更改列的属性(除了重命名列之外)。 You will have to :- 你不得不 :-

  1. Rename the child table. 重命名子表。
  2. Create the replacement table using the original name with the change and then use INSERT INTO replacement_table_with_original_name SELECT * FROM renamed_table (obviously changing replacement_table_with_original_name and renamed_table ) to the actual names. 使用原来的名字与变化创建替换表,然后使用INSERT INTO replacement_table_with_original_name SELECT * FROM renamed_table (明显改变replacement_table_with_original_namerenamed_table)实际名称。
  3. When happy DROP the renamed table. 当高兴时,DROP重命名表。

Example

For example consider the following representation of your scenario (from the available information) then this will add the ON UPDATE CASCADE and ON DELETE CASCADE whilst keeping the existing data, it additionally deletes a row without conflict and also updates a referenced value without conflict or loss :- 例如,考虑场景的以下表示形式(从可用信息中得出),这将在保留现有数据的同时添加ON UPDATE CASCADEON 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
;

Results :- 结果:-

The log :- 日志:-

-- 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

Result 1 (base data) 结果1(基础数据)

在此处输入图片说明

Result 2 (after schema change) 结果2(架构更改后)

在此处输入图片说明

Result 3 (after delete) 结果3(删除后)

在此处输入图片说明

Result 4 (after update) 结果4(更新后)

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM