Die Hitze setzt mir zu und vernebelt meine MySQL-Kentnisse.
Ich habe folgendes vor:
1. Tabelle mit Daten (id, name, content, kategorie_id, datum (als unix timestamp) usw..) nennen wir sie mal tabelle_1
2. Tabelle mit Kategorien (id, name, ttl (in Tagen)) hier tabelle_2
ttl ist das maximale Alter der Detaildatensätze aus tabelle_1 für die jeweilige Kategorie. Ich möchte nun per Cronjob die Datensätze aus tabelle_1 löschen wenn deren Alter den Wert ttl in tabelle_2 überschritten hat.
Ich habe es mit folgendem Statement versucht:
DELETE FROM tabelle_1 WHERE id IN ( SELECT t1.id FROM tabelle_1 t1 LEFT JOIN tabelle_2 t2 ON t1.kategorie_id = t2.id WHERE ( UNIX_TIMESTAMP( ) - t1.datum ) > ( t2.ttl * 86400 ) )
Das ganze wird mir quittiert mit:
#1093 - Die Verwendung der zu aktualisierenden Zieltabelle 'tabelle_1' ist in der FROM-Klausel nicht zulässig.
Du darfst in einem 'inner select' nicht die Tabelle verwenden aus der Du löschen willst. Das geht einfach nicht ;)
Versuch mal so (ungetestet):
DELETE FROM tabelle_1 t1 WHERE UNIX_TIMESTAMP()-t1.datum > (SELECT ttl FROM tabelle2 WHERE id=t1.kategorie_id) * 86400
Ansonsten musst Du zweistufig arbeiten: 1) Alle (kat_id,TTL) Paare holen 2) Für alle Paare aus tab1 löschen (ein grosses query basteln oder einzelne queries)
[edit] Geht übrigens übersichtlicher (wenn datum vom Typ DateTime ist): datum < NOW() - INTERVAL ttl DAY [/edit]
Oder du arbeitest eine Stored Procedure aus der du die Daten übergibst. Natürlich inkl. Rollback möglichkeit.
Beispiel aus unserer Produktion:
create procedure item_update(IN id INT(20), IN name VARCHAR(50), IN price float(10,2), OUT ret TINYINT) begin declare exit handler for not found rollback; declare exit handler for sqlwarning rollback; declare exit handler for sqlexception rollback;
set ret=0; start transaction
-- insert into ... -- update ... -- any other DDL operation
commit;
set ret = 1; end
was du der Funktion übergeben willst ist dir überlassen, vorteil ist das man sich im Code gar nicht mehr um die Selects kümmern muss und trotzdem sicher bleibt.
So wie er allerdings seinen Tabellen Aufbau beschreibt sehe ich nicht wie er das lösen kann, denn das liest sich wie:
Tabelle 1 -> Items der WaWi: ID (des Items), Name, Kat_id, Datum des Hinzufügens Tabelle 2 -> Kategorien: ID (von der Kategorie), Namen,Datum wann das letzte Item hinzugefügt wurde
Ein Item sollte eigentlich nur einmal in einer Kategorie sein. Möchte ich mehrere Kategorien, darf ich nicht von der Kategorie auf das Item referenzieren weil eine n:m beziehung besteht. Ich würde nur auf das Item Alter gehen und die Kategorie nur als Info verwenden.
Danke für dein Posting, aber ne stored procedure ist nicht ganz unproblematisch, da ich die Datenbank mit einer selbsgebauten PHP-DB-Klasse anspreche, die arge Probleme mit stored-procedures hat. (SP erscheint mir für diese simple Aufgabe auch etwas übertrieben).
Das Statement von DaSpors funktioniert nach der oben genannten Korrektur bestens.
Noch eine Möglichkeit: Erweitere Tabelle1 um ein Feld valid_until und schreibe dort beim Erstellen des Items oder beim Einordnen in eine Kategorie einen Kategorie.TTL abhängigen Wert rein. Oder mach es für alle:
UPDATE tab1 t1 SET t1.valid_until = t1.created + INTERVAL (SELECT ttl FROM tab2 t2 WHERE t2.id=t1.kat_id) DAY
in etwas abgewandeleter from erledigt es jedoch seine aufgabe bestens.
Das korrekte Statement lautet:
DELETE FROM tabelle_1 WHERE
(UNIX_TIMESTAMP() - tabelle1.datum) > ((SELECT t2.ttl FROM tabelle2 t2 WHERE t2.id=tabelle1.kategorie_id) * 86400)