Wojciech Szabowicz
Wojciech Szabowicz

Reputation: 4198

Merging multiple databases with relations in SQLite

I have couple of sqlite files (databases) with rather simple structure like:

  | Id | Category |                                | Id | CatId | Name |
  -----------------                                ---------------------
  | 1  |     A    |                                | 1  |   2   |  A   |
  -----------------  -- relations one to many  --> ---------------------
  | 2  |     B    |                                | 2  |   1   |  B   |
                                                   ---------------------
                                                   | 3  |   2   |  BC  |

So as you see there is a table with categories witch is related to name tabe. Problem is I have couple of sutrch file and i want to merge them into one and keep relations.

So merging first table is simple like:

ATTACH DATABASE '{databaseFilePath}' AS Db;

BEGIN;
INSERT INTO Category (Category) SELECT Category FROM Db.Category;
COMMIT;

DETACH DATABASE Db;

But this will change my id (it is set to autoincrement because in many db files there can have same id). Now I can do the same for second table with names, problem is with keeping relation as primary has changed. Is there any rational way to do this?

Here is create tables:

CREATE TABLE Category (Id INTEGER PRIMARY KEY NOT NULL UNIQUE,Category STRING);
INSERT INTO Category (Category, Id) VALUES ('B', 2), ('A', 1);

CREATE TABLE Name (Id INTEGER PRIMARY KEY UNIQUE NOT NULL, 
CatId INTEGER 
REFERENCES Category (Id) ON DELETE CASCADE ON UPDATE CASCADE MATCH SIMPLE, Name  STRING);
INSERT INTO Name (Name,CatId,Id)VALUES ('A',1,1),('AB',1,3 ),('B',2,2);

Upvotes: 1

Views: 217

Answers (1)

MikeT
MikeT

Reputation: 56943

I believe that you could base it on the following (instead of attaching the database, 2 has been appended to the 2nd set of table names (for convenience), additionally the data has been prefixed with C2 for the 2nd set of tables) :-

DROP TABLE IF EXISTS Name;
DROP TABLE IF EXISTS Name2;
DROP TABLE IF EXISTS Category;
DROP TABLE IF EXISTS Category2;

CREATE TABLE Category (Id INTEGER PRIMARY KEY NOT NULL UNIQUE,Category STRING);
INSERT INTO Category (Category, Id) VALUES ('B', 2), ('A', 1);

CREATE TABLE Name (Id INTEGER PRIMARY KEY UNIQUE NOT NULL, 
CatId INTEGER 
REFERENCES Category (Id) ON DELETE CASCADE ON UPDATE CASCADE MATCH SIMPLE, Name  STRING);
INSERT INTO Name (Name,CatId,Id)VALUES ('A',1,1),('AB',1,3 ),('B',2,2);

CREATE TABLE Category2 (Id INTEGER PRIMARY KEY NOT NULL UNIQUE,Category STRING);
INSERT INTO Category2 (Category, Id) VALUES ('C2B', 2), ('C2A', 1);

CREATE TABLE Name2 (Id INTEGER PRIMARY KEY UNIQUE NOT NULL, 
CatId INTEGER 
REFERENCES Category2 (Id) ON DELETE CASCADE ON UPDATE CASCADE MATCH SIMPLE, Name  STRING);
INSERT INTO Name2 (Name,CatId,Id)VALUES ('C2A',1,1),('C2AB',1,3 ),('C2B',2,2);

UPDATE Category2 SET id = id + (Max((SELECT max(id) FROM Category),(SELECT max(id) FROM Category2)));
UPDATE Name2 SET id = id + (Max((SELECT Max(id) FROM name) ,(SELECT max(id) FROM name2)));

SELECT * FROM Category2;
SELECT * FROM Name2;
INSERT INTO Category SELECT * FROM Category2 WHERE 1;
INSERT INTO name SELECT * FROM name2 WHERE 1;
SELECT * FROM Category;
SELECT * FROM Name;
  • Note you mention AUTOINCREMENT but haven't included it, so checking for the highest sqlite_sequence value hasn't been included.
  • The above relies upon the CASCADE On UPDATE, to cascade the increase to the Category.id down to the CatId.

This works by finding the highest id of both tables with the same schema and then updating the id's of the table to be merged by adding the found highest id to the id's of all rows. When the tables are the Category table the updated ID's are cascaded to the respective Name table.

The process is performed for both the pair of Category tables and the pair of Name tables.

The result (the last query is) :-

enter image description here

Upvotes: 1

Related Questions