Wie lösche ich die obersten 1000 Zeilen mit SQL Server 2008 aus einer Tabelle?

108

Ich habe eine Tabelle in SQL Server. Ich möchte die obersten 1000 Zeilen daraus löschen. Ich habe dies jedoch versucht, aber anstatt nur die obersten 1000 Zeilen zu löschen, wurden alle Zeilen in der Tabelle gelöscht.

Hier ist der Code:

delete from [mytab] 
select top 1000 
a1,a2,a3
from [mytab]
edgarmtze
quelle
8
Sie benötigen eine ORDER BY, um TOP aussagekräftig zu machen: Siehe die Antwort von @Martin Smith, die die einzige von fünf ist, die dies hat. Ich verzweifle manchmal
gbn
2
Wollen Sie löschen alle 1000 Zeilen? Nur zufällig ausgewählt? Oder zum Beispiel die 1000 ältesten Zeilen?
Nick Chammas
13
Sie haben die gesamte Tabelle gelöscht, da delete from [mytab]es sich um eine Anweisung und select top ...eine andere handelt.
Nick Chammas
2
Sie brauchen keine Bestellung für Top, hängt davon ab, warum Sie TOP machen. Wenn Sie 10 Millionen Zeilen entfernen müssen und 1 GB Protokollspeicherplatz zur Verfügung haben, verwenden Sie Delete TOP (10000) From dbo.myTable (mit Ihrer select-Klausel) und führen Sie es weiter aus, bis keine Zeilen mehr gelöscht werden müssen. Wen kümmert es, wenn es willkürlich ist. Das Sortieren verlangsamt nur die Abfrage.
Tvanharp
1
Mir ist klar, dass dies eine alte Frage ist (in SO Jahren), aber ich denke, dass es wichtig ist, dass die Leute die Kommentare von @gbn berücksichtigen . Obwohl seine Kommentare nicht auf meine gegebene Situation zutreffen (versuchen, Datensatzblöcke zu löschen, ohne LOCK-Probleme zu verursachen, sich aber nicht wirklich um die Reihenfolge kümmern, in der sie gelöscht werden), können sie sehr wahrscheinlich auf IHRE Situation zutreffen. Stellen Sie sicher, dass Sie sie berücksichtigen, bevor Sie die folgenden Antworten blind verwenden, die keine ORDER BY-Klausel enthalten.
Andrew Steitz

Antworten:

195

Der Code, den Sie ausprobiert haben, besteht aus zwei Anweisungen. A DELETEgefolgt von a SELECT.

Sie definieren nicht, TOPnach was geordnet.

Für ein bestimmtes Bestellkriterium ist das Löschen aus einem CTE oder einem ähnlichen Tabellenausdruck der effizienteste Weg.

;WITH CTE AS
(
SELECT TOP 1000 *
FROM [mytab]
ORDER BY a1
)
DELETE FROM CTE
Martin Smith
quelle
13
Wenn Sie sich fragen, warum Sie dies nicht tun können DELETE TOP (1000) FROM table ORDER BY column, lesen Sie Folgendes : "Die Zeilen, auf die im TOP-Ausdruck verwiesen wird, der mit INSERT, UPDATE, MERGE oder DELETE verwendet wird, sind nicht in beliebiger Reihenfolge angeordnet."
Nick Chammas
3
@ Magnus ja. Nicht 2000. Es könnte möglich sein, eine abgeleitete Tabelle im Jahr 2000 zu verwenden. Ich habe keine Instanz zum Testen.
Martin Smith
2
Ich hatte einen etwas anderen Weg eingeschlagen (obwohl ich denke, dass der CTE besser anzusehen ist): DELETE T1 FROM (SELECT TOP 1000 * FROM [MYTAB] ORDER BY A1) T1;
Abacus
4
@Liam - nur weil, wenn vor dem CTE eine vorhergehende Aussage vorliegt, diese mit einem Semikolon beendet werden muss, das an die Vorderseite der WITHBeschwerden von Personen angehängt wird, die dies nicht getan haben.
Martin Smith
86

Kann für sql2005 + besser sein:

DELETE TOP (1000)
FROM [MyTab]
WHERE YourConditions

Für Sql2000:

DELETE FROM [MyTab]
WHERE YourIdField IN 
(
  SELECT TOP 1000 
    YourIdField 
  FROM [MyTab]
  WHERE YourConditions
)

ABER

Wenn Sie eine bestimmte Teilmenge von Zeilen anstelle einer beliebigen Teilmenge löschen möchten , sollten Sie die Reihenfolge der Unterabfrage explizit angeben:

DELETE FROM [MyTab]
WHERE YourIdField IN 
(
  SELECT TOP 1000 
    YourIdField 
  FROM [MyTab]
  WHERE YourConditions
  ORDER BY ExplicitSortOrder
)

Vielen Dank an tp @gbn für die Erwähnung und Forderung der klareren und genaueren Antwort.

Oleg Dok
quelle
3
@gbn Vielleicht nutzlos für dich, aber genau das ist es, wonach die Frage fragt.
Joachim Isaksson
1
@ Joachim Isaksson: Lesen Sie mehr über TOP und kommen Sie dann zurück. Es gibt kein TOP ohne ORDER BY in Sets. Alternativ können Sie mir eine kanonische Referenz suchen, die mir das Gegenteil
2007/07/19
1
@gbn Keine Bedingungen bezüglich der zu löschenden Zeilen, daher ist ORDER BY in Unterabfrage nutzlos
Oleg Dok
1
@gbn Hast du WHERE in der Unterabfrage erwähnt? Ich filtere 1000 beliebige Zeilen innerhalb der ausgewählten Kriterien und lösche sie dann. Gültiges Szenario? Ja. Wenn ich ORDER BY NEWID () hinzufüge oder was auch immer es nichts ändert - ich lösche immer noch 1000 Zeilen, die nach ausgewählten Kriterien gefiltert sind
Oleg Dok
8
@gbn Wenn Sie nach einer gültigen Verwendung von TOP ohne ORDER BY suchen: Was mich hierher gebracht hat, ist, dass ich alle Zeilen löschen muss, die einigen Kriterien entsprechen, aber aus Leistungsgründen möchte ich nicht, dass mehr als 10.000 Zeilen gelöscht werden zu einer Zeit. Es ist mir egal, welche Zeilen gelöscht werden, da ich den Befehl in einigen Intervallen erneut ausführen werde, bis alle diese Zeilen verschwunden sind.
Richiban
6
delete from [mytab]
where [mytab].primarykeyid in
(
select top 1000 primarykeyid
from [mytab]
)
Jason Dam
quelle
4
Nutzlos: TOP ohne ORDER BY gibt beliebige Zeilen
gbn
4
@gbn Vielleicht nutzlos für dich, aber genau das ist es, wonach die Frage fragt.
Joachim Isaksson
3
@gbn Ich habe nicht behauptet, dass es eine Standardsortierreihenfolge gibt oder dass die Abfrage in irgendeiner Weise nützlich ist. Ich habe Sie nur daran erinnert, dass die Frage nicht nach einer gefragt hat. Was würden Sie also für eine Bestellung vorschlagen?
Joachim Isaksson
2
@gbn Ich weiß nicht, warum du in Bezug auf etwas, das ein Ausgangspunkt ist, so feindlich gegenüber allen bist. Ich behaupte nicht, dass meine Antwort das Ende aller ist, es ist nur ein Vorschlag, jemandem zu helfen. Ich denke, die Wichtigkeit sind die Schlüssel, die von der Unterabfrage hier zurückkommen.
Jason Dam
2
Dies kann alles sein, wonach der Fragesteller sucht. Ich möchte nur eine Notiz für andere Leser hinzufügen, um zu betonen, dass die durch eine solche Anweisung gelöschten Zeilen nicht garantiert in beliebiger Reihenfolge sind.
Nick Chammas
3
SET ROWCOUNT 1000;

DELETE FROM [MyTable] WHERE .....
Joe Bourne
quelle
2
Ist es wirklich wichtig, wenn es sich nur um 1000 Zeilen handelt? Wenn es 100.000.000 Zeilen wären, wären Ihre Punkte möglicherweise gültig, aber für nur 1000 Zeilen ist dies bei weitem die einfachste Lösung, die bisher für SQL 2008 vorgeschlagen wurde.
Joe Bourne
1

Es ist schnell. Versuch es:

DELETE FROM YourTABLE
FROM (SELECT TOP XX PK FROM YourTABLE) tbl
WHERE YourTABLE.PK = tbl.PK

YourTABLEDurch Tabellennamen ersetzen , XXdurch eine Zahl, z. B. 1000, pkist der Name des Primärschlüsselfelds Ihrer Tabelle.

Hamed Elahi
quelle
Sie erstellen effektiv zwei Tabellen aus einer und löschen dann, wo verbunden. Dies funktioniert gut, wenn Sie die ältesten (oder neuesten) Datensätze aus einer Tabelle löschen möchten, da Sie sie zuerst aufsteigend sortieren können. Dieses T-SQL wird von Microsoft akzeptiert (und es ist schnell).
Tequila