Löschen Sie alle außer top n aus der Datenbanktabelle in SQL

84

Was ist der beste Weg, um alle Zeilen aus einer Tabelle in SQL zu löschen, aber n Zeilen oben zu halten?

Riri
quelle

Antworten:

79
DELETE FROM Table WHERE ID NOT IN (SELECT TOP 10 ID FROM Table)

Bearbeiten:

Chris bringt einen guten Leistungstreffer hervor, da die TOP 10-Abfrage für jede Zeile ausgeführt wird. Wenn dies eine einmalige Sache ist, dann ist es vielleicht keine so große Sache, aber wenn es eine übliche Sache ist, dann habe ich es mir genauer angesehen.

Cory Foy
quelle
4
Wenn jemand normalerweise alle bis auf die obersten n Zeilen löschen muss, würde ich behaupten, dass er größere Probleme hat, über die er sich Sorgen machen muss.
Daniel Schaffer
6
Nur ein Hinweis, dass Sie das Leistungsproblem der Unterabfrage lösen können, indem Sie entweder manuell eine temporäre Tabelle erstellen (vorausgesetzt, dies ist eine seltene Operation) oder die Abfrage schreiben DELETE FROM Table WHERE ID NOT IN (SELECT id FROM (SELECT TOP 10 ID FROM Table) AS x), um MySQL zu zwingen, eine temporäre Tabelle zu erstellen.
Michael Mior
Danke dir. Das war ein Lebensretter :)
Si8
1
Die Unterabfrage wird mehrmals ausgeführt, stimmt das? stackoverflow.com/questions/18790796/…
djluis
5
@ Daniel Schaffer Hört sich nicht so an, als hätten sie ein Problem mit der Datenbank oder der Geschäftslogik. Klingt nach einer völlig normalen Aufbewahrungsrichtlinie.
Hejazzman
32

Ich würde ID-Spalte (n) der Reihe von Zeilen auswählen, die Sie in einer temporären Tabelle oder Tabellenvariablen behalten möchten. Löschen Sie dann alle Zeilen, die in der temporären Tabelle nicht vorhanden sind. Die von einem anderen Benutzer erwähnte Syntax:

DELETE FROM Table WHERE ID NOT IN (SELECT TOP 10 ID FROM Table)

Hat ein potentielles Problem. Die Abfrage "SELECT TOP 10" wird für jede Zeile in der Tabelle ausgeführt, was einen großen Leistungseinbruch bedeuten könnte. Sie möchten vermeiden, dass immer wieder dieselbe Abfrage durchgeführt wird.

Diese Syntax sollte funktionieren, basierend auf dem, was Sie als Ihre ursprüngliche SQL-Anweisung aufgeführt haben:

create table #nuke(NukeID int)

insert into #nuke(Nuke) select top 1000 id from article

delete article where not exists (select 1 from nuke where Nukeid = id)

drop table #nuke
Chris Miller
quelle
2
insert into #nuke(Nuke) ...sollte wohl sein: insert into #nuke(NukeID) ...Auch der Name nuke ist verwirrend, weil Sie versuchen, diese Zeilen NICHT zu löschen. nuke ist wahrscheinlich nach der Tatsache benannt, dass es gelöscht wird.
Erno
12

Zukünftige Referenz für Benutzer, die kein MS SQL verwenden.

Verwenden Sie in PostgreSQL ORDER BYund LIMITanstelle von TOP.

DELETE FROM table
WHERE id NOT IN (SELECT id FROM table ORDER BY id LIMIT n);

MySQL - na ja ...

Fehler - Diese Version von MySQL unterstützt die Unterabfrage 'LIMIT & IN / ALL / ANY / SOME' noch nicht.

Noch nicht, denke ich.

Simurr
quelle
5

Ich denke, die Verwendung einer virtuellen Tabelle wäre viel besser als eine IN-Klausel oder eine temporäre Tabelle.

DELETE 
    Product
FROM
    Product
    LEFT OUTER JOIN
    (
        SELECT TOP 10
            Product.id
        FROM
            Product
    ) TopProducts ON Product.id = TopProducts.id
WHERE
    TopProducts.id IS NULL
Tim Wilson
quelle
2

Ich weiß nichts über andere Geschmacksrichtungen, aber MySQL DELETE erlaubt LIMIT.

Wenn Sie die Dinge so bestellen könnten, dass die n Zeilen, die Sie behalten möchten, unten sind, könnten Sie eine DELETE FROM-Tabelle LIMIT tablecount-n ausführen.

Bearbeiten

Oooo. Ich denke, ich mag Cory Foys Antwort besser, vorausgesetzt, es funktioniert in Ihrem Fall. Mein Weg fühlt sich im Vergleich etwas klobig an.

Mark Biek
quelle
2

Dies wird wirklich sprachspezifisch sein, aber ich würde wahrscheinlich Folgendes für SQL Server verwenden.

declare @n int
SET @n = SELECT Count(*) FROM dTABLE;
DELETE TOP (@n - 10 ) FROM dTable

Wenn Sie sich nicht für die genaue Anzahl der Zeilen interessieren, gibt es immer

DELETE TOP 90 PERCENT FROM dTABLE;
Noah
quelle
1
Keine dieser Arbeiten. In der Frage wird gefragt, wie nur die obersten N Zeilen in einer Tabelle beibehalten werden sollen. Beide Beispiele behalten nur die unteren N Zeilen bei.
Chris
1
Funktioniert gut in MSSQL. Fügen Sie einfach eine Sortierung hinzu, um die Unterseite anstelle der Oberseite zu löschen?
MeanGreen
2

Hier ist, wie ich es gemacht habe. Diese Methode ist schneller und einfacher:

Löschen Sie alle bis auf das oberste n aus der Datenbanktabelle in MS SQL mit dem Befehl OFFSET

WITH CTE AS
    (
    SELECT  ID
    FROM    dbo.TableName
    ORDER BY ID DESC
    OFFSET 11 ROWS
    )
DELETE CTE;

Ersetzen Sie IDdurch eine Spalte, nach der Sie sortieren möchten. Ersetzen Sie die Nummer nach OFFSETdurch die Anzahl der Zeilen, die Sie löschen möchten. Wählen Sie DESCoder ASC- was auch immer zu Ihrem Fall passt.

Harvey
quelle
0

Ich würde es mit der folgenden Technik lösen. Das Beispiel erwartet eine Artikeltabelle mit einer ID in jeder Zeile .

Delete article where id not in (select top 1000 id from article)

Edit: Zu langsam um meine eigene Frage zu beantworten ...

Riri
quelle
0

Überarbeitet?

Delete a From Table a Inner Join (
    Select Top (Select Count(tableID) From Table) - 10) 
        From Table Order By tableID Desc
) b On b.tableID = A.tableID

edit: habe beide im Query Analyzer ausprobiert, aktuelle Antwort wird gefastet (verdammte Reihenfolge von ...)

Shawn
quelle
0

Besser wäre es, die gewünschten Zeilen in eine andere Tabelle einzufügen, die ursprüngliche Tabelle zu löschen und die neue Tabelle so umzubenennen, dass sie denselben Namen wie die alte Tabelle hat

SQLMenace
quelle
Warum ist das besser? Schneller? Erfordert einige zusätzliche Befehle.
MeanGreen
0

Ich habe einen Trick, um zu vermeiden, dass der TOPAusdruck für jede Zeile ausgeführt wird. Wir können kombinieren TOPmit MAXdem bekommen MaxIdwir behalten wollen. Dann löschen wir einfach alles größer als MaxId.

-- Declare Variable to hold the highest id we want to keep. 
DECLARE @MaxId as int = (
SELECT MAX(temp.ID)
FROM (SELECT TOP 10 ID FROM table ORDER BY ID ASC) temp
)

-- Delete anything greater than MaxId. If MaxId is null, there is nothing to delete.
IF @MaxId IS NOT NULL
    DELETE FROM table WHERE ID > @MaxId

Hinweis: Es ist wichtig, ORDER BYbei der Deklaration MaxIdzu verwenden , um sicherzustellen, dass die richtigen Ergebnisse abgefragt werden.

Clamchoda
quelle