MySQL Tabellen vergleichen

Matze

Weltenwanderer
Hi.

Ich arbeite gerade an einem Programm, dass die Daten zweier MySQL Tabellen vergleichen soll. Die Tabellen sind von der Struktur her gleich und haben einen Primärschlüssel.

Ich weiß jetzt allerding nicht so genau, wie ich den Verlgeich angehen soll. Am ende soll eine Liste mit allen sich unterscheidenden Datensätzen (aber gleichem Primärschlüssel), eine Liste mit Daten, die nur in der einen Tabelle vorkommen und umgekehrt.
Die Tabellen können auch seeehr groß sein, deshalb weiß ich nicht wie ich da am besten vorgehe.

Für Vorschläge währe ich sehr dankbar.
 
Ich würde dir folgendes Vorgehen vorschlagen:

Du erstellst dir ein Objekt, welches deine Tabelle repräsentiert. Also alle Spalten (außer des Primärschlüssels) sollten da vorhanden sein. In dem Objekt erstellst du eine Methode isEqual die als Argument ein Objekt vom gleichen Typ erwartet. In dieser Methode definierst du dann, wann ein Objekt gleich dem anderen ist.

Jetzt zur Datenbank:
Es gibt nun unterschiedliche Methoden, aber wenn du genug RAM hast, kannst du es folgendermaßen machen. Du holst alle (oder die Hälfte, vierteil, 1000, 100) Zeilen aus beiden Datenbanken raus und machst aus allen ein Objekt. Du packst es dann anschließend in eine HashMap<int,Objektname> rein, wobei du als Schlüssel der HashMap den Primärschlüssel der Tabelle verwendest.

Jetzt hast du zwei Listen, die beide Tabellen beinhalten. Um den Vergleich nun schneller abzuschließen, musst du feststellen, welche Map mehr Objekte beinhaltet. Die größe findest du einfach mit .size() heraus. Dann gehst du in einer einfachen (ersten) for Schleife alle Objekte der größeren Liste durch und in der zweiten for schleife gehst du die Objekte der zweiten, kleineren Liste durch. Im inneren der beiden Schleifen hast du dann einen Vergleich. if(a.get(i).isEqual(b.get(j)){ a.remove(a.get(i)); b.remove(b.get(i)); }

Eventuell musst du noch überprüfen, ob es tatsächlich ein Objekt zum Key gibt, containsKey(key) macht das für dich.

Das wars, dann hast du am Ende zwei Maps mit einer Symmetrischen Differenz.
 
Hey
@port29: Dein Vorschlag, wie du ja schon selbst sagst, ist sehr Ressourcenfressend. Für die grösse meiner DBs wahrscheindlich zu ressourcenfressend..
@Matze: Ich würde einfach mit Abfragen arbeiten. z.B.:

Unterscheide:
SQL:
Select tbl1.*, tbl2.* from tbl1
inner join tbl2 on tbl1.id=tbl2.id
where tbl1.att1<>tbl2.att1 or tbl1.att2<>tbl2.att2 or #(weitere Attribute vergleichen);

Die, die nur in tbl1 vorkommen
SQL:
Select tbl1.* from tbl1
left join tbl2 on tbl1.id=tbl2.id
where tbl2.id is null;

Die, die nur in tbl2 vorkommen
SQL:
Select tbl2.* from tbl2
left join tbl1 on tbl1.id=tbl2.id
where tbl1.id is null;

So ist die Arbeit auf den Datenbankserver ausgelagert und ich denke das ist schneller als in Java alles mit equals durchgehen.

Wenn es statisch ist (also immer die gleichen Tabellen sind) kannst du die Abfragen ja vorgefertigt im Code einbetten. Ansonsten kann du dir die oben aufgezeigten Abfragen auch relativ einfach zusammen basteln in dem du zuerst mit show tables zuerst die Tabellen holst und dann pro Tabelle mit show create tables die zu vergleichenden Attribute holst.

Hoffe ist verständlich :D Ansonsten einfach nochmals nachfragen

Gruss

PS: Wenns dynamisch (also für alle möglichen Tabellen) anwendbar ist würde mich das Tool auch interessieren
 
Hab gerade noch ein paar Performanceübeungen für die Unterschiede-Abfrage gemacht.

Da du ja nachher wissen willst welche Attribute unterschiedlich sind und wahrscheindlich auch gleich die Attribute zur Verfügung haben willst würde ich es so machen:
SQL:
Select tbl1.att1<>tbl2.att1 as Unt_att1, tbl1.att1, tbl2.att1  #jeweils 3 Einträge pro Attribut
tbl1.att2<>tbl2.att2 as Unt_att2, tbl1.att2, tbl2.att2 #Unt_att*=1 wenn unterschiedlich
FROM tbl1
INNER JOIN tbl2 ON tbl1.id=tbl2.id 
#where Teil lasse ich weg, da er die "<>"-Vergleiche sonst nochmals rechnen müsste
having Unt_att1=1 or Unt_att2=1 #damit du im ResultSet nur die hast die ihrgendwo unterschiedlich sind

Viel Erfolg
 
Zuletzt bearbeitet:
Ich hätt da auch noch nen Vorschlag :-)

SQL:
select * from (
    select * from tabelle1
    UNION ALL
    select * from tabelle2
)

group by 1,2,3,4, ... n // wobei 1 = PrimaryKey und n Anzahl der Spalten
having count(*) != 2
 
Erstmal vielen Dank für die Vorschläge.
Es sollte schon den Speicher etwas schonen, da die Tabellen auch riesig sein können. Und ja, es soll dynamisch sein. Am Ende soll eine JavaPage rauskommen die ungefähr so aussieht wie auf dem ScreenShoot. Unterschiede sollen deutlich gemacht werden. Der User soll anschließend wählen können, ob er die Unterschiede ignorriert oder den Datensatz einer der Tabellen an den Anderen angleichen will.

Leider kamm gerade ein dringenderer Auftrag dazwischen, so dass ich damit frühestens Freitag beginnen kann.
 

Anhänge

  • Beispiel.jpg
    Beispiel.jpg
    31,5 KB · Aufrufe: 160
Oh.. Union, interessanter Ansatz ;) Einer der wenigen MySQL Befehle die ich noch fast nie verwendet habe.

Mit einem order by ID kann man immer zwei aufeinanderfolgende Datensätze vergleichen ;)
 
Mit einem order by ID kann man immer zwei aufeinanderfolgende Datensätze vergleichen

Könnte man - bis einem die Augen weh tun :-)

Man kann's aber auch die Datenbank für einen erledigen lassen.

Du wirst ja wahrscheinlich eh zur Auswahl anbieten, welche Felder für einen Vergleich relevant sein sollen, den Primary Key kann man ermitteln.
Dann ist es ein leichtes, diese Felder im Select und im group by anzugeben.

Mehr als gleiche 2 Datensätze: In einer der Tabellen ist die ID doppelt vergeben
Weniger als 2 Datensätze: Fehlende Übereinstimmung
2 Datensätze: passt alles, oder Datensatz in einer Tabelle komplett doppelt vorhanden

Dazu noch ein order by, dass alle Fehler der gleichen ID beieinander liegen und das sollte schon mal viel bieten.
 
Zurück