I'm developing mobile app for learning a foreign language using flutter
and sqflite
package. The app has sqlite
database with tables for words and some kind of collections (relation many to many). 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
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. 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.
I think I need some kind of cascade id update in sqlite insert or replace
, but there is no such feature.
Any ideas, please?
I think I need some kind of cascade id update in sqlite insert or replace, but there is no such feature.
There is such a feature; you specify ON UPDATE CASCADE
as part of the FOREIGN KEY definition/clause. You can also code ON DELETE CASCADE
SQLite Foreign Key Support - 4.3. ON DELETE and ON UPDATE Actions .
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). You will have to :-
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. 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 :-
-- 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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.