# mysql: Datensätze aus zwei Tabellen vergleichen



## Sprint (17. Dezember 2018)

Hallo zusammen,

ich habe hier eine Kundentabelle, bei der die Datensätze vor einem Update immer in eine Backup Tabelle kopiert werden um später feststellen zu können, ob sich in der Zwischenzeit an relevanten Feldern etwas geändert hat. Ich habe es jetzt hiermit probiert:

```
SELECT kdnr
FROM   kunden k
       LEFT OUTER JOIN kundenhistory h
                    ON k.kdnr = h.kdnr
WHERE  k.vorname = h.vorname
       AND k.nachname = h.nachname
       AND k.firmenname = h.firmenname
       AND k.strasse = h.strasse
       AND k.hausnr = h.hausnr
       AND k.plz = h.plz
       AND k.ort = h.ort
       AND k.kdnr = 200001
```
Allerdings bekomme ich verständlicherweise den Fehler, daß kdnr in der History nicht eindeutig ist. Kann ich aber auch nicht sein, da ja mehrere Generationen von Backups auftreten können.
Eindeutig werden die Zeilen in der History durch eine laufende Nummer "backupid". Zudem wird der Zeitpunkt des Backups in einem Feld "backupdatum" festgehalten. Bei dem Vergleich soll immer mit dem neuesten Backup verglichen werden.

Kann mir da jemand bitte auf die Sprünge helfen?


----------



## Yaslaw (17. Dezember 2018)

Mit einer Unterabfrage die aktuellen Daten des Backups auslesen. Also der Letzte.

[SQL] Aktuelle Einträge pro Gruppe auslesen [Yaslaw.Info]


----------



## Sprint (17. Dezember 2018)

Ich habe es jetzt so lösen können:

```
SELECT k.kdnr
FROM   kunden k,
        (select nachname, vorname, firmenname, strasse, hausnr, plz, ort, max(backupdatum)
        from kundenhistory) as h
WHERE  (k.vorname != h.vorname
       OR k.nachname != h.nachname
       OR k.firmenname != h.firmenname
       OR k.strasse != h.strasse
       OR k.hausnr != h.hausnr
       OR k.plz != h.plz
       OR k.ort != h.ort)
       AND k.kdnr = h.kdnr
```
Zumindest bekomme ich bei den ersten Tests die richtigen Ergebnisse. 

Vielen Dank für deine Hilfe!


----------



## Sprint (18. Dezember 2018)

Leider doch nicht. 

Ich habe die Abfrage noch etwas erweitern müssen, aber auch ohne die Erweiterung nimmt er nur den ersten Datensatz. Wenn erst im zweiten oder dritten eine Unterscheidung auftaucht, wird die nicht gefunden.

```
SELECT     k.kdnr, kv.kvid
FROM    kunden k,
        kaufvertrag kv,
        (SELECT kdnr, nachname, vorname, firmenname, strasse, hausnr, plz, ort, max(backupdatum)
        FROM kundenhistory) as h
WHERE    (k.vorname != h.vorname
        OR k.nachname != h.nachname
        OR k.firmenname != h.firmenname
        OR k.strasse != h.strasse
        OR k.hausnr != h.hausnr
        OR k.plz != h.plz
        OR k.ort != h.ort)
        AND k.kdnr = h.kdnr
        AND kv.kplok = 0
        AND kv.storno = 0
        AND kv.kdnr = k.kdnr
```
Ich habe auch schon mit den OR bzw. != experimentiert, bringt aber auch nichts.

Ziel ist es, die Kunden- und Kaufvertragsnummern herauszufinden, bei denen sich in Adresse oder Namen etwas geändert hat, während der Handel noch nicht abgeschlossen ist.


----------



## Yaslaw (18. Dezember 2018)

Ist logisch. Schau nochmals mein Tutorial an.
Nur den MAX-Wert zu nehmen macht noch gar nix. Die History-Daten mit dem Max-Wert zur Kundennummer filtern

Das sind die notwendigen Backupdaten, die du zum vergleichen brauchst

```
select kh.*
from 
    kundenhistory kh,
    (
        select kdnr, max(backupdatum) as max_datum
        from kundenhistory
        group by kdnr
    ) khmax
where kh.kdnr = khmax.kdnr and kh.backupdatum = khmax.max_datum
```


----------



## Sprint (18. Dezember 2018)

Ich muß ganz ehrlich gestehen, daß die SQL Scripte etwas zu hoch sind. So ganz kapiere ich nicht, was da passiert.
Inzwischen hatte ich aber noch mit der JOIN Variante experimentiert, da mir eingefallen war, daß es ja auch Kunden geben kann, die trotz Änderungen keine offenen Kaufverträge haben und die dürfen natürlich nicht mit ausgegeben werden.
Zusammen mit deinem letzten Hinweis bin ich jetzt zu dieser Abfrage gekommen, die mir jetzt zumindest das richtige Ergebnis auch über mehrere Datensätze ausgibt. Ich habe zu ein paar Kunden eine History angelegt, von denen zwei einen offenen KV haben und genau die beiden werden ausgegeben.

```
SELECT    k.kdnr, kv.kvid
FROM    kaufvertrag kv,
        kunden k
INNER JOIN (select kdnr, nachname, vorname, firmenname, strasse, hausnr, plz, ort, max(backupdatum) as max_datum
        from kundenhistory
        GROUP BY kdnr) as h
        ON k.kdnr = h.kdnr
WHERE    (k.vorname != h.vorname
        OR k.nachname != h.nachname
        OR k.firmenname != h.firmenname
        OR k.strasse != h.strasse
        OR k.hausnr != h.hausnr
        OR k.plz != h.plz
        OR k.ort != h.ort)
        AND kv.kplok = 0
        AND kv.storno = 0
        AND kv.kdnr = k.kdnr
```
Wie gesagt, es soll der aktuelle Kundendatensatz mit der jüngsten History verglichen werden, aber nur die ausgegeben werden, die noch einen offenen KV haben.


----------



## Yaslaw (18. Dezember 2018)

Mein Hinweis hast du regelrecht ignoriert. Naja, egal.


----------



## Sprint (18. Dezember 2018)

Yaslaw hat gesagt.:


> Nur den MAX-Wert zu nehmen macht noch gar nix. Die History-Daten mit dem Max-Wert zur Kundennummer filtern


Meintest du den? Ignoriert habe ich ihn nicht, nur vergessen.
Wie gesagt, ich war damit beschäftigt, das ganze auf JOIN umzustellen, um die Kaufverträge mit reinzubringen. Außerdem muß ja auch noch die aktuelle Kundentabelle mit rein, da ja noch der Vergleich mit den aktuellen Kundendaten fehlte. Wenn ich das aber jetzt noch mit reinnehme, bekomme ich die Fehlermeldung, daß k.kdnr in der ON Clause unbekannt ist.

```
SELECT    k.kdnr, kv.kvid
FROM    kunden k,
        kundenhistory h,
        kaufvertrag kv
INNER JOIN (select kdnr, nachname, vorname, firmenname, strasse, hausnr, plz, ort, max(backupdatum) as max_datum
        from kundenhistory
        GROUP BY kdnr) as hmax
        ON k.kdnr = h.kdnr
WHERE    (k.vorname != hmax.vorname
        OR k.nachname != hmax.nachname
        OR k.firmenname != hmax.firmenname
        OR k.strasse != hmax.strasse
        OR k.hausnr != hmax.hausnr
        OR k.plz != hmax.plz
        OR k.ort != hmax.ort)
        AND kv.kplok = 0
        AND kv.storno = 0
        AND kv.kdnr = k.kdnr
        AND k.kdnr = hmax.kdnr
        AND h.backupdatum = hmax.max_datum
```
Ich hab da auch schon alle möglichen Reihenfolgen durchprobiert, bekomme aber immer den selben Fehler.


----------



## Yaslaw (18. Dezember 2018)

Kannst du mir das erklären? Macht keinen Sinn:

```
(select kdnr, nachname, vorname, firmenname, strasse, hausnr, plz, ort, max(backupdatum) as max_datum
        from kundenhistory
        GROUP BY kdnr)
```
MySQL verzeit zu viele Fehler. Bei allen anderen Datenbanken währe das ein Fehler.
Du gruppierst nach der kdnr. Gut.
Du berechnest das Maximum vom Datum. Gut.
Wenn gruppiert wird, was macht MySQL mit den anderen Feldern? Soll dort ein Zufallswert genommen werden? Oder danach gruppiert werden? MySQL gruppiert danach.
Ergo hast du im Endeffekt das:

```
(select kdnr, nachname, vorname, firmenname, strasse, hausnr, plz, ort, max(backupdatum) as max_datum
        from kundenhistory
        GROUP BY kdnr, nachname, vorname, firmenname, strasse, hausnr, plz, ort)
```
Und somit gruppierst du allen Änderungen auf den Feldern. Das gibt pro Änderung eine Zeile.

Zum Vergleich:

```
select kh.*
from 
    kundenhistory kh,
    (
        select kdnr, max(backupdatum) as max_datum
        from kundenhistory
        group by kdnr
    ) khmax
where kh.kdnr = khmax.kdnr and kh.backupdatum = khmax.max_datum
```
Da wird zuerst pro kdn das aktuellste Datum ermittelt und mit dem dann die entsprechenden Datensätze ermittelt. Das gibt wirklich pro kdnr den aktuellsten Backup


----------



## Sprint (18. Dezember 2018)

Ich geb dir vollkommen Recht, das ergibt keinen Sinn.
Nur habe ich nach wie vor das Problem, daß ich den Fehler auf die k.kdnr on der ON Clause bekomme.


----------



## Yaslaw (18. Dezember 2018)

Du mischst JOIN und Verknüpfungen mit WHERE. AMch entweder oder.


----------

