Du kannst keine direkte Bedingung an das
DELETE anhängen.
Das hat folgende Gründe:
Die Bedingung basiert auf der Tabelle in der gelöscht wird. Die Bedingung lässt sich (wenn überhaupt) über ein Subquery erzeugen. Ein Subquery für ein manipulierendes Query darf aber nicht auf die gleiche Tabelle zugreifen. Dadurch werden mögliche Endlosschleifen und damit ein Absturz des Datenbankservers verhindert.
Desweiteren solltest Du bedenken, dass ein Subquery nur mit MySQL >= 4.1 funktioniert.
Auf jeden Fall solltest Du mit Transaktionen bzw. einer Read-Sperre (schließt eine Write-Sperre ein) arbeiten, da Du zwei Queries benötigst.
Als erstes solltest Du Dir Gedanken über ein Select-Statement machen, welches die zu löschenden Datensätze selektiert. Dazu unten mehr. Da liegt IMHO derzeit das größte Problem. Hast Du dieses, projezierst Du nur den Primärschlüssel und erzeugst damit eine temporäre Tabelle.
In die Bedingung des
Delete schreibst Du dann:
SQL:
DELETE
#...
WHERE primärschlüssel IN (SELECT primärschlüssel FROM tempTable)
Hast Du MySQL < 4.1, sparst Du Dir die temporäre Tabelle und liest die Primärschlüssel aus. Diese schreibst Du komma-seperiert in einen String und fügst ihn statt des Subqueries ein.
Hast Du einen zusammengesetzten Primärschlüssel (p1 bis pn), musst Du alle Felder des Primärschlüssels projezieren und ihn in der Bedingung getrennt behandeln, mit
and verknüpft. In etwa so:
SQL:
DELETE
#...
WHERE p1 IN (SELECT p1 FROM tempTable)
AND p2 IN (SELECT p2 FROM tempTable)
#...
AND pn IN (SELECT pn FROM tempTable)
Der Workaround ist dann entsprechend, Du kannst natürlich dann alle gemeinsam projezieren und in getrennten Strings verarbeiten.
Das Select-Statement solltest Du zunächst unabhängig von dem Delete entwickeln und auf seine Richtigkeit überprüfen.
Evtl. wird es einfacher, die negierte Bedingung zu selektieren, also alle Datensätze zu suchen, die bestehen bleiben sollen und dann mit
NOT IN zu arbeiten.
Nun zu dem Select:
Auch das ist IMHO nicht ohne Subquery zu machen. Ggf. findet sich auch hier ein Workaround, so dass es auch in MySQL < 4.1 machbar ist.
Ich würde wie folgt heran gehen (ich abstrahiere mal ein bisschen von Deiner Tabelle und der nötigen Projektion):
Zuerst ist der hundertste Datensatz eines jeden Users zu finden:
SQL:
SELECT * FROM
Tabelle t1
WHERE t1.Zeit=(SELECT min(t2.Zeit) FROM Tabelle t2
WHERE t2.UserID=t1.UserID
GROUP BY t2.UserID
ORDER BY Zeit DESC
LIMIT 100)
So erhältst Du den ältesten Datensatz zu jedem User, der noch bestehen bleiben soll.
Wenn Du das
t1.Zeit= jetzt in ein
t1.Zeit>= verwandelst und die Projektion auf den Primärschlüssel beschränkst, solltest Du alle Primärschlüssel erhalten, die zu den Datensätzen gehören, die Du behalten willst:
SQL:
SELECT
p1,
#..
pn
FROM Tabelle t1
WHERE t1.Zeit>=(SELECT min(t2.Zeit) FROM Tabelle t2
WHERE t2.UserID=t1.UserID
ORDER BY Zeit DESC
LIMIT 100)
Schau am Besten erst mal, was bei dem Query rumkommt und ob es Deinen Bedingungen genügt.
Wichtig ist vor allem, dass Deine Zeit in einem "sortierfähigen" Format vorliegt, also entweder als MySQL-Datetime oder als Integer, der einen Unix-Timestamp repräsentiert.
Außerdem kann es bei dieser Vorgehensweise dazu kommen, dass über 100 Einträge beibehalten werden, wenn die Eintragungen an der Schnittstelle zu 100 Einträgen eines Users sekundengenau zeitgleich erfolgt sind.
Gruß hpvw