4

There are two solutions provided (see links at the bottom), but both fail in what i'm trying to do:

1. Given tables (identical) structure in databases like for example this:

DB1

Fruit
--------------
| id | name  |
--------------
| 1  | Apple |
| 2  | Lemon |
| 3  | Kiwi  |
| 4  | Banana|
--------------
Juice
----------------
| id | name    |
----------------
| 1  | Juice A |
| 2  | Juice B |
----------------
Recipe (Junction Table)
----------------------------
| id | juice_id | fruit_id |
----------------------------
| 1  | 1        | 1        |
| 2  | 1        | 2        |
| 3  | 2        | 1        |
| 4  | 2        | 3        |
----------------------------

DB2

Fruit
---------------
| id | name   |
---------------
| 1  | Kiwi   |
| 2  | Lemon  |
| 3  | Apple  |
| 4  | Orange |
| 5  | Lime   |
---------------
Juice
----------------
| id | name    |
----------------
| 1  | Juice C |
| 2  | Juice D |
----------------
Recipe (Junction Table)
----------------------------
| id | juice_id | fruit_id |
----------------------------
| 1  | 1        | 1        |
| 2  | 1        | 3        |
| 3  | 2        | 2        |
| 4  | 2        | 4        |
----------------------------

2. convert them into this:

DB3

Fruit
|----------------|
| id | name      |
|----------------|
| 1  | Kiwi      |
| 2  | Lemon     |
| 3  | Apple     |
| 4  | Orange    |
| 5  | Lime      |
| 6  | Banana    |
------------------
Juice
|--------------|
| id | name    |
|--------------|
| 1  | Juice A |
| 2  | Juice B |
| 3  | Juice C |
| 4  | Juice D |
----------------
Recipe (Junction Table)
----------------------------
| id | juice_id | fruit_id |
----------------------------
| 1  | 1        | 3        |
| 2  | 1        | 2        |
| 3  | 2        | 3        |
| 4  | 2        | 1        |
++++++++++++++++++++++++++++
| 5  | 3        | 1        |
| 6  | 3        | 3        |
| 7  | 4        | 2        |
| 8  | 4        | 4        |
----------------------------

Please notice that fruit id's changed accordingly, preserving relations despite change in fruit ID. ID is primary integer autoincrementing key, and Recipe contains two foregin keys (plus own primary integer autoincrementing key).

3. only two proposed solutions are:

a)

$sqlite3 database1.db '.dump' >> tmp
$sqlite3 database2.db '.dump' >> tmp
$sqlite3 database3.db '.import tmp'
$ #sometimes sqlite3 database3.db < 'tmp' instead of last row

from 4, and simmilar questions, and:

b)

$ sqlite3 newdb
attach 'b.db' as toMerge;   
BEGIN; 
insert into newdb select * from toMerge.sometable; 
COMMIT;

Other answers ie. 1, 2, 3, 4, 5, 6, 7 just repeat same pattern. Perhaps 6 might be solution but i couldnt tell, the lenght of that query frightened me...

Moreover, as 1 states there is no gui compare & merge solution. At least besides 2011 sqlitecompare, which probably works in Windows anyway (i'm looking for Linux tool) Some opinions in 8 also confirm that hardly any userfriendly gui has merge option.

So, question is. How to merge sqlite DB in Linux, keeping relations, but not keeping duplicate values from tags / notes? I'd thought that keeping organized structure is the main reason for keeping things in database, but it seems I fail to understand, why should i keep two same fruits in one basket if combining from two baskets. My basket should contain unique fruits and recipies, I want to eat that kiwi :)

Community
  • 1
  • 1
user3264463
  • 43
  • 1
  • 1
  • 3
  • I have not read all 8 answers, yours itself is an epic TL;DR. I have however a suggestion. When you create a new table for fruit and juice, add db1id and db2id columns. During insert populate the columns from db1 and db2 respectively (there will be either one, or two, or both populated). Copy data from db1 and db2 to recipe1 and recipe2 respectively AS THEY ARE. Now, you need to insert data to your recipe table using a simple statement which you will be able to write in a matter of seconds (when you have all the tables in front of your eyes) – cha Feb 03 '14 at 06:25
  • @CL Read carefully. That post said nothing about not discarding duplicates. cha - true, but imho good description can hopefully reduce amount of people asking for the same thing. Modular questions/answers comesto mind. I actually did read more than 9 related questions, cause, where CL is wrong again, it is not homework, and i cared about solution. So i'll check josepn's and accept if it'll work. – user3264463 Feb 03 '14 at 19:03

1 Answers1

5
PRAGMA foreign_keys = on;

ATTACH DATABASE 'db1.sqlite' AS db1;

ATTACH DATABASE 'db2.sqlite' AS db2;

BEGIN;

CREATE TABLE Fruit      (
                          id            INTEGER PRIMARY KEY NOT NULL,
                          name          TEXT    UNIQUE ON CONFLICT IGNORE
                          )
                          ;

CREATE TABLE Juice      (
                          id            INTEGER PRIMARY KEY NOT NULL,
                          name          TEXT    UNIQUE ON CONFLICT IGNORE
                        )
                        ;

CREATE TABLE Recipe     (
                          id            INTEGER PRIMARY KEY NOT NULL,
                          juice_id      INTEGER NOT NULL,
                          fruit_id      INTEGER NOT NULL,
                          FOREIGN KEY   ( juice_id ) REFERENCES Juice ( id )
                                        ON UPDATE CASCADE
                                        ON DELETE CASCADE,
                          FOREIGN KEY   ( fruit_id ) REFERENCES Fruit ( id )
                                        ON UPDATE CASCADE
                                        ON DELETE CASCADE
                        )
                        ;


INSERT INTO Fruit  ( id, name )               SELECT id, name FROM db1.Fruit;
INSERT INTO Juice  ( id, name )               SELECT id, name FROM db1.Juice;
INSERT INTO Recipe ( id, juice_id, fruit_id ) SELECT id, juice_id, fruit_id FROM db1.Recipe;

INSERT INTO Fruit ( name ) SELECT name FROM db2.Fruit;
INSERT INTO Juice ( name ) SELECT name FROM db2.Juice;

CREATE TEMPORARY TABLE Recipe_tmp AS
                                    SELECT Juice.name AS j_name, Fruit.name AS f_name
                                      FROM db2.Recipe, db2.Fruit, db2.Juice
                                        WHERE db2.Recipe.juice_id = db2.Juice.id AND db2.Recipe.fruit_id = db2.Fruit.id
;

INSERT INTO Recipe ( juice_id, fruit_id ) SELECT j.id, f.id
                                            FROM Recipe_tmp AS r, Juice AS j, Fruit AS f
                                              WHERE r.j_name = j.name AND r.f_name = f.name
;


DROP TABLE Recipe_tmp;

COMMIT;

DETACH DATABASE db1;
DETACH DATABASE db2;
josepn
  • 377
  • 4
  • 5
  • WOW. I will happily accept this as answer, provided it works, as it is closest to complete solution (though sadly crude=iter). Sure it is raw sql but might get to be faster than programmed solutions, and some might even like it this way better. I wonder about two things : problems with fks when there already are nonunique vals... And since i have also indexes on foregin keys, i presume i'd need to recreate them for sake of completness to above answer? Hmm, and another, last thing. Insert into Recipe from db1. Why do You take also id, isn't it better to allow sqlite to renumerate ? – user3264463 Feb 03 '14 at 21:01
  • So it did mostly work - by that i mean, if anything did not work it was my fault, as I needed to tweak it also to my schema. What else stumblings i had - which may be lesson to anyone else? Actually, if You dont pass any argument to sqlite3 it operates on memory, which may/maynot be faster, but to "save" to file you need to do .backup filename at the end of script. Also, You can pass this script as "whole", or execute ".read scriptname" Anyway - I've learned much. Thank You @josepn. – user3264463 Feb 03 '14 at 21:02
  • @user3264463 - It is an exact copy of the first database. With If this is not so important that it is better to allow the growing sqlite id – josepn Feb 04 '14 at 08:25