Sie können die Datensätze nicht auf diese Weise löschen. Das Hauptproblem besteht darin, dass Sie keine Unterabfrage verwenden können, um den Wert einer LIMIT-Klausel anzugeben.
Dies funktioniert (getestet in MySQL 5.0.67):
DELETE FROM `table`
WHERE id NOT IN (
SELECT id
FROM (
SELECT id
FROM `table`
ORDER BY id DESC
LIMIT 42 -- keep this many records
) foo
);
Die Zwischenunterabfrage ist erforderlich. Ohne sie würden wir auf zwei Fehler stoßen:
- SQL-Fehler (1093): Sie können die Zieltabelle 'Tabelle' für die Aktualisierung in der FROM-Klausel nicht angeben. Mit MySQL können Sie nicht auf die Tabelle verweisen, aus der Sie in einer direkten Unterabfrage löschen.
- SQL-Fehler (1235): Diese Version von MySQL unterstützt die Unterabfrage 'LIMIT & IN / ALL / ANY / SOME' noch nicht. Sie können die LIMIT-Klausel nicht in einer direkten Unterabfrage eines NOT IN-Operators verwenden.
Glücklicherweise können wir durch die Verwendung einer Zwischenunterabfrage diese beiden Einschränkungen umgehen.
Nicole hat darauf hingewiesen, dass diese Abfrage für bestimmte Anwendungsfälle (wie diesen) erheblich optimiert werden kann. Ich empfehle auch, diese Antwort zu lesen , um zu sehen, ob sie zu Ihrer passt.
Ich weiß, dass ich eine ziemlich alte Frage wiederbelebe, aber ich bin kürzlich auf dieses Problem gestoßen, brauchte aber etwas, das sich gut auf große Zahlen skalieren lässt . Es gab keine vorhandenen Leistungsdaten, und da diese Frage einige Aufmerksamkeit auf sich gezogen hat, dachte ich, ich würde das posten, was ich gefunden habe.
Die Lösungen, die tatsächlich funktionierten, waren die doppelte
NOT IN
Unterabfrage / Methode von Alex Barrett (ähnlich der von Bill Karwin ) und dieLEFT JOIN
Methode von Quassnoi .Leider erstellen beide oben genannten Methoden sehr große temporäre Zwischentabellen, und die Leistung nimmt schnell ab, da die Anzahl der nicht gelöschten Datensätze groß wird.
Was ich beschlossen habe, verwendet Alex Barretts doppelte Unterabfrage (danke!), Verwendet aber
<=
anstelle vonNOT IN
:Es wird verwendet
OFFSET
, um die ID des N- ten Datensatzes abzurufen und diesen Datensatz und alle vorherigen Datensätze zu löschen.Da die Bestellung bereits eine Annahme dieses Problems ist (
ORDER BY id DESC
),<=
passt sie perfekt.Dies ist viel schneller, da die von der Unterabfrage generierte temporäre Tabelle nur einen Datensatz anstelle von N Datensätzen enthält.
Testfall
Ich habe die drei Arbeitsmethoden und die neue Methode oben in zwei Testfällen getestet.
Beide Testfälle verwenden 10000 vorhandene Zeilen, während der erste Test 9000 (löscht die ältesten 1000) und der zweite Test 50 (löscht die ältesten 9950) behält.
Interessant ist, dass die
<=
Methode auf der ganzen Linie eine bessere Leistung erzielt, aber tatsächlich besser wird, je mehr Sie behalten, anstatt schlechter.quelle
ROW_NUMBER()
: stackoverflow.com/questions/603724/…Leider können Sie für alle Antworten anderer Leute nicht
DELETE
undSELECT
aus einer bestimmten Tabelle in derselben Abfrage.MySQL kann auch
LIMIT
keine Unterabfrage unterstützen. Dies sind Einschränkungen von MySQL.Die beste Antwort, die ich finden kann, ist, dies in zwei Schritten zu tun:
Sammeln Sie die IDs und machen Sie sie zu einer durch Kommas getrennten Zeichenfolge:
(Normalerweise birgt das Interpolieren einer durch Kommas getrennten Liste in eine SQL-Anweisung ein gewisses Risiko für eine SQL-Injection. In diesem Fall stammen die Werte jedoch nicht aus einer nicht vertrauenswürdigen Quelle, sondern sind ganzzahlige Werte aus der Datenbank selbst.)
Hinweis: Obwohl dies nicht in einer einzigen Abfrage erledigt wird , ist manchmal eine einfachere Lösung am effektivsten.
quelle
DELETE FROM mytable WHERE id NOT IN (SELECT id FROM mytable ORDER BY id DESC LIMIT 3);
einwandfrei.quelle
Wenn Ihre ID inkrementell ist, verwenden Sie so etwas wie
quelle
Um alle Datensätze mit Ausnahme des letzten N zu löschen , können Sie die unten angegebene Abfrage verwenden.
Es ist eine einzelne Abfrage, aber mit vielen Anweisungen, so dass es eigentlich keine einzelne Abfrage ist, wie es in der ursprünglichen Frage beabsichtigt war.
Außerdem benötigen Sie aufgrund eines Fehlers in MySQL eine Variable und eine integrierte (in der Abfrage) vorbereitete Anweisung.
Hoffe es kann trotzdem nützlich sein ...
nnn sind die zu behaltenden Zeilen und theTable ist die Tabelle, an der Sie arbeiten.
Ich gehe davon aus, dass Sie einen automatisch inkrementierenden Datensatz mit dem Namen id haben
Das Gute an diesem Ansatz ist die Leistung : Ich habe die Abfrage in einer lokalen Datenbank mit etwa 13.000 Datensätzen getestet, wobei die letzten 1.000 beibehalten wurden. Es läuft in 0,08 Sekunden.
Das Skript aus der akzeptierten Antwort ...
Dauert 0,55 Sekunden. Etwa 7 mal mehr.
Testumgebung: mySQL 5.5.25 auf einem i7 MacBookPro mit SSD Ende 2011
quelle
quelle
versuchen Sie unten Abfrage:
Die innere Unterabfrage gibt den Top-10-Wert zurück und die äußere Abfrage löscht alle Datensätze mit Ausnahme der Top-10.
quelle
DELETE FROM table WHERE id NICHT IN (SELECT id FROM table ORDER BY id, desc LIMIT 0, 10)
quelle
Dies sollte auch funktionieren:
quelle
Wie wäre es mit :
Es werden Zeilen mit mehr als N Zeilen zurückgegeben. Könnte nützlich sein?
quelle
Die Verwendung von id für diese Aufgabe ist in vielen Fällen keine Option. Zum Beispiel - Tabelle mit Twitter-Status. Hier ist eine Variante mit angegebenem Zeitstempelfeld.
quelle
Ich wollte dies nur für jeden in den Mix werfen, der Microsoft SQL Server anstelle von MySQL verwendet. Das Schlüsselwort 'Limit' wird von MSSQL nicht unterstützt, daher müssen Sie eine Alternative verwenden. Dieser Code funktionierte in SQL 2008 und basiert auf diesem SO-Beitrag. https://stackoverflow.com/a/1104447/993856
Zugegeben, das ist nicht elegant. Wenn Sie dies für Microsoft SQL optimieren können, teilen Sie Ihre Lösung mit. Vielen Dank!
quelle
Wenn Sie die Datensätze auch basierend auf einer anderen Spalte löschen müssen, finden Sie hier eine Lösung:
quelle
Warum nicht
Löschen Sie einfach alle bis auf die erste Zeile (Reihenfolge ist DESC!) Und verwenden Sie eine sehr sehr große Zahl als zweites LIMIT-Argument. Siehe hier
quelle
DELETE
unterstützt nicht[offset],
oderOFFSET
: dev.mysql.com/doc/refman/5.0/en/delete.htmlNach langer Zeit darauf zu antworten ... Kam über die gleiche Situation und anstatt die genannten Antworten zu verwenden, kam ich mit -
Dadurch werden die ersten 10 Datensätze gelöscht und die neuesten Datensätze aufbewahrt.
quelle