Как объединить две базы данных sqlite без потери внешних ключей? - PullRequest
0 голосов
/ 10 июля 2019

Я занимаюсь разработкой мобильного приложения для изучения иностранного языка с использованием пакетов flutter и sqflite.Приложение имеет sqlite базу данных с таблицами слов и некими коллекциями (отношение многих ко многим).Эти данные хранятся в активе приложения и загружаются в каталог мобильных баз данных при установке приложения, как в руководстве по sqflite https://github.com/tekartik/sqflite/blob/master/sqflite/doc/opening_asset_db.md
Пользователь может добавлять собственные слова и коллекции, а также я хочу заполнить или изменить мои.Раньше я думал, что могу достичь этого с помощью sqlite upsert, но в случае, если этот пользователь добавил то же слово, что и я в обновлении приложения, возникает конфликт.Если я сделаю upsert, то это слово не появится в моих коллекциях слов, потому что они связаны идентификатором, в противном случае, если я сделаю replace, то слово исчезнет из коллекций пользователя.

Я думаю, что мне нужнокакое-то каскадное обновление идентификатора в sqlite insert or replace, но такой функции нет.

Есть идеи, пожалуйста?

1 Ответ

0 голосов
/ 11 июля 2019

Я думаю, мне нужно какое-то каскадное обновление идентификатора в sqlite insert заменить, но такой функции нет.

Есть такая функция; вы указываете ON UPDATE CASCADE как часть определения / предложения FOREIGN KEY. Вы также можете кодировать ON DELETE CASCADE Поддержка внешнего ключа SQLite - 4.3. ON DELETE и ON UPDATE Действия .

Так как это закодировано как часть дочерней таблицы, и вы не можете использовать ALTER TABLE COLUMN для изменения атрибутов столбца (кроме как для RENAME столбца). Вам придется: -

  1. Переименуйте дочернюю таблицу.
  2. Создайте таблицу замены, используя исходное имя с изменением, а затем используйте INSERT INTO replacement_table_with_original_name SELECT * FROM renamed_table (очевидно, изменяющееся replace_table_with_original_name и renamed_table ) к реальным именам.
  3. Когда счастливый DROP переименовывает таблицу.

Пример

Например, рассмотрите следующее представление вашего сценария (из доступной информации), тогда это добавит 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

Результат 1 (базовые данные)

enter image description here

Результат 2 (после изменения схемы)

enter image description here

Результат 3 (после удаления)

enter image description here

Результат 4 (после обновления)

enter image description here

...