
94451
20.06.2012, aktualisiert am 22.06.2012
MySQL Doppelte elemente löschen! Ältestes element beibehalten!
Hallo,
ich habe Grundlegende PHP und MySQL fähigkeiten aber dafür reichts dann leider doch nicht!
ich habe eine Tabelle und die schaut ca. so aus!
ID |. Auftrags_NR | Unterauftrag | Status | LASTCHANGE
1 .|. 123 ..............| 1 ...............| 100 .....| 2012-06-19 07:49:12
2 .|. 123 ..............| 1 ...............| 100 .....| 2012-06-19 07:51:10
3 .|. 123 ..............| 1 ...............| 100 .....| 2012-06-19 07:52:05
4 .|. 125 ..............| 1 ...............| 100 .....| 2012-06-19 08:01:55
5 .|. 125 ..............| 1 ...............| 200 .....| 2012-06-19 08:02:12
ID -> INDEX,... immer anders in diesen Fall uninsteressant!
Die Schlüsselwerte für das Suchen und Löschen sind Auftrags_Nr, Unterauftrag und Status! LASTCHANGE ist das Datum andem der Datensatz das letzte mal geändert wurde
(klingt komisch, ist aber so).
Ich suche eine Funktion die feststellt das (wie im Beispiel) ID 1, 2 und 3 gleich sind und dann alle doppelten Werte löscht (außer dem ältesten -> ID 1).
mein ansatz:
$delete_twice = "DELETE FROM tabelle WHERE ... ORDER BY LASTCHANGE ASC LIMIT 1, 99";
Aber irgendwie find ich keine richtige bedingung!
Vielen Dank für euere Unterstützung
Beste Grüße
RoadRunner
ich habe Grundlegende PHP und MySQL fähigkeiten aber dafür reichts dann leider doch nicht!
ich habe eine Tabelle und die schaut ca. so aus!
ID |. Auftrags_NR | Unterauftrag | Status | LASTCHANGE
1 .|. 123 ..............| 1 ...............| 100 .....| 2012-06-19 07:49:12
2 .|. 123 ..............| 1 ...............| 100 .....| 2012-06-19 07:51:10
3 .|. 123 ..............| 1 ...............| 100 .....| 2012-06-19 07:52:05
4 .|. 125 ..............| 1 ...............| 100 .....| 2012-06-19 08:01:55
5 .|. 125 ..............| 1 ...............| 200 .....| 2012-06-19 08:02:12
ID -> INDEX,... immer anders in diesen Fall uninsteressant!
Die Schlüsselwerte für das Suchen und Löschen sind Auftrags_Nr, Unterauftrag und Status! LASTCHANGE ist das Datum andem der Datensatz das letzte mal geändert wurde
Ich suche eine Funktion die feststellt das (wie im Beispiel) ID 1, 2 und 3 gleich sind und dann alle doppelten Werte löscht (außer dem ältesten -> ID 1).
mein ansatz:
$delete_twice = "DELETE FROM tabelle WHERE ... ORDER BY LASTCHANGE ASC LIMIT 1, 99";
Aber irgendwie find ich keine richtige bedingung!
Vielen Dank für euere Unterstützung
Beste Grüße
RoadRunner
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Kommentar vom Moderator Biber am 22.06.2012 um 16:02:05 Uhr
Verschoben von PHP nach Datenbanken.
Content-ID: 186731
Url: https://administrator.de/forum/mysql-doppelte-elemente-loeschen-aeltestes-element-beibehalten-186731.html
Ausgedruckt am: 04.04.2025 um 06:04 Uhr
24 Kommentare
Neuester Kommentar
außer dem ältesten
.. sagen wir mal: "dem ersten" ?Du brauchst eine Liste mit allen "ersten" IDs.
SELECT * FROM Tabelle
GROUP BY Auftrags_NR
Nun machst mit dieser Ergebnismenge ein LEFT JOIN über die Tabelle und prüfst auf NULL
SELECT ID FROM Table t1 LEFT JOIN (
SELECT * FROM Tabelle
GROUP BY Auftrags_NR
) t2 ON (t1.ID = t2.ID)
WHERE t2 IS NULL
nun hast du die Liste der zu löschenden Datensätze
DELETE FROM Table WHERE ID IN (
SELECT ID FROM Table t1 LEFT JOIN (
SELECT * FROM Tabelle
GROUP BY Auftrags_NR
) t2 ON (t1.ID = t2.ID)
WHERE t2 IS NULL
)
..ungetestet - so ich arbeite mal weiter...
EDIT: gehört eigentlich zu MySQL / Datenbanken - dieses Problem
Hallo,
ich denke es sollte wie folgt funktionieren:
Gruß Jörg
ich denke es sollte wie folgt funktionieren:
DELETE FROM tabelle c
WHERE c.ID NOT IN (SELECT a.ID
FROM tabelle a
INNER JOIN (SELECT t.AUFTRAGS_NR, t.UNTERAUFTRAG, t.STATUS, MIN(t.LASTCHANGE) AS LC
FROM tabelle t
GROUP BY t.AUFTRAGS_NR, t.UNTERAUFTRAG, t.STATUS) b
ON a.AUFTRAGS_NR = b.AUFTRAGS_NR
AND a.UNTERAUFTRAG = b.UNTERAUFTRAG
AND a.STATUS = b.STATUS
AND a.LASTCHANGE = b.LC)
Gruß Jörg
Zitat von @94451:
ja OK,... aber warum sollte es fatal sein, wenn ich nicht sortiere wärend ich gruppiere?
und, ja leider bekomm ichs nicht hin!
wie genau muss ich die Abfrage aufbauen?
ja OK,... aber warum sollte es fatal sein, wenn ich nicht sortiere wärend ich gruppiere?
und, ja leider bekomm ichs nicht hin!
wie genau muss ich die Abfrage aufbauen?
... man Sortiert nicht während des Gruppierens.
Sondern es werden die Datensätze nach dem Gruppieren sortiert.
Von daher glaube ich nicht, dass die Aussage aus dem 1. Post
..sollte schon reichen, da MySQL wohl immer die nicht im GROUP oder in einer Aggregat Funktion gepackten Felder, den > ersten gefundenen Datensatz zurück gibt.
funktioniert.
Gruß Jörg
ein Group BY ohne ORDER wäre in diesem Fall sehr fatal.
... man Sortiert nicht während des Gruppierens.
Sondern es werden die Datensätze nach dem Gruppieren sortiert.
... ein GROUP löst autom. auch ein ORDER über die angegebenen Felder aus.... man Sortiert nicht während des Gruppierens.
Sondern es werden die Datensätze nach dem Gruppieren sortiert.
Man müsste sogar:
GROUP BY Feld
ORDER BY NULL
ABER: das ORDER nach dem GROUP ist eh nicht wichtig - wenn dann müsste das ORDER vor dem Gruppieren gemacht werden.
Das Beispiel sollte funktionieren, WENN: die Daten in LASTCHANGE auch der Reihenfolge beim Speichern in der DB entsprechen. Ansonsten muss man vorher noch ein SUB SELECT mit ORDER ausführen.
EDIT: in Post 1 ist ein Fehler:
/* SELECT * FROM Table WHERE ID IN ( */
DELETE FROM Table WHERE ID IN (
SELECT t1.ID FROM Table t1 LEFT JOIN (
SELECT * FROM Tabelle
GROUP BY Auftrags_NR
) t2 ON (t1.ID = t2.ID)
WHERE t2.ID IS NULL
)
mit Verbesserung:
/* SELECT * FROM Table WHERE ID IN ( */
DELETE FROM Table WHERE ID IN (
SELECT t1.ID FROM Table t1 LEFT JOIN (
SELECT tmp.* FROM ( SELECT * FROM Table ORDER BY LASTCHANGE ) tmp
GROUP BY tmp.Auftrags_NR
) t2 ON (t1.ID = t2.ID)
WHERE t2.ID IS NULL
)
... bei der oberen fehlt der "*" nach dem SELECT und bei der unteren hast Du das reservierte Wort "Table" verwendet.
Habe gerade auf meiner Oracle-Datenbank genau die Anweisung ohne Fehlermeldung abgesetzt.
Gruß Jörg
SELECT c.* FROM cd_status c
WHERE c.ID NOT IN (SELECT a.ID
FROM cd_status a
INNER JOIN (SELECT t.AUFTRAGS_NR, t.UNTERAUFTRAG, t.STATUS, MIN(t.LASTCHANGE) AS LC
FROM cd_status t
GROUP BY t.AUFTRAGS_NR, t.UNTERAUFTRAG, t.STATUS) b
ON a.AUFTRAGS_NR = b.AUFTRAGS_NR
AND a.UNTERAUFTRAG = b.UNTERAUFTRAG
AND a.STATUS = b.STATUS
AND a.LASTCHANGE = b.LC)
Habe gerade auf meiner Oracle-Datenbank genau die Anweisung ohne Fehlermeldung abgesetzt.
SELECT c.* FROM ifsapp.inventory_transaction_hist c
WHERE c.transaction_id NOT IN (SELECT a.transaction_id
FROM ifsapp.inventory_transaction_hist a
INNER JOIN (SELECT t.order_no, t.release_no, t.line_item_no,
MIN(t.date_created) AS LC
FROM ifsapp.inventory_transaction_hist t
GROUP BY t.order_no, t.release_no, t.line_item_no) b
ON a.order_no = b.order_no
AND a.release_no = b.release_no
AND a.line_item_no = b.line_item_no
AND a.date_created = b.LC)
Gruß Jörg
OK, er scheint kein Subselect mit der Tabelle zu mögen, aus der Zeilen gelöscht werden sollen.
Das heißt, Du musst Dir die zu löschenden ID mittels
in eine temporäre Tabelle speichern und dann ...
Am Ende noch weg mit der Temp-Tabelle
Gruß Jörg
Das heißt, Du musst Dir die zu löschenden ID mittels
CREATE TABLE tmp_cd_status_id
SELECT c.ID from cd_status c
WHERE c.ID NOT IN (...)
in eine temporäre Tabelle speichern und dann ...
DELETE FROM cd_status
WHERE ID IN (SELECT ID FROM tmp_tabelle)
Am Ende noch weg mit der Temp-Tabelle
DROP TABLE tmp_cd_status_id
Gruß Jörg
You can't specify target table 'cd_status' for update in FROM clause
hab ich ne falsche MySQL version?
er scheint kein Subselect mit der Tabelle zu mögen,
... es handelt sich wohl um MyISAM Tabellen - diese sind zwar schnell beim ändern von Daten, müssen dazu aber die betreffende Tabelle sperren. Ein SELECT während des UPDATEs / DELETEs ist somit nicht möglich.hab ich ne falsche MySQL version?
er scheint kein Subselect mit der Tabelle zu mögen,
EDIT:
Sollte es sich um sehr viele zu löschende Daten handeln, könnte man die zu erhaltenen Daten auch in die temp. Tabelle übertragen. Danach ein TRUNCATE ausführen (TRANCATE ist sehr viel schneller) und anschließend die Daten wieder einspielen.