Comment supprimer les 1000 premières lignes d'une table à l'aide de Sql Server 2008?

108

J'ai une table dans SQL Server. Je voudrais en supprimer les 1000 premières lignes. Cependant, j'ai essayé cela, mais au lieu de simplement supprimer les 1000 premières lignes, j'ai supprimé toutes les lignes du tableau.

Voici le code:

delete from [mytab] 
select top 1000 
a1,a2,a3
from [mytab]
edgarmtze
la source
8
Vous avez besoin d'un ORDER BY pour rendre TOP significatif: voir la réponse de @Martin Smith qui est la seule sur cinq à avoir cela. Je désespère parfois
gbn
2
Voulez - vous supprimer toutes les 1000 lignes? Juste choisi au hasard? Ou, par exemple, les 1000 premières lignes les plus anciennes?
Nick Chammas
13
Vous avez supprimé toute la table car delete from [mytab]c'est une instruction et select top ...une autre.
Nick Chammas
2
Vous n'avez pas besoin de commander pour top, cela dépend de la raison pour laquelle vous faites TOP. Si vous avez besoin de supprimer 10 millions de lignes et d'avoir 1 Go d'espace de journal disponible, utilisez Delete TOP (10000) From dbo.myTable (avec votre clause select) et continuez à l'exécuter jusqu'à ce qu'il n'y ait plus de lignes à supprimer. Qui se soucie si c'est arbitraire. Le tri ne fait que ralentir la requête.
tvanharp le
1
Je me rends compte que c'est une question ancienne (depuis quelques années) mais je pense qu'il est important que les gens prennent en compte les commentaires de @gbn . Bien que ses commentaires ne s'appliquent pas à ma situation donnée (essayer de supprimer des blocs d'enregistrements sans causer de problèmes de VERROUILLAGE mais ne pas vraiment se soucier de l'ordre dans lequel ils sont supprimés), ils peuvent très probablement s'appliquer à VOTRE situation. Assurez-vous de les prendre en compte avant d'utiliser aveuglément les réponses ci-dessous qui n'incluent pas de clause ORDER BY.
Andrew Steitz

Réponses:

196

Le code que vous avez essayé est en fait deux déclarations. Un DELETEsuivi d'un SELECT.

Vous ne définissez pas TOPcomme ordonné par quoi.

Pour un critère de classement spécifique, la suppression d'une expression de table CTE ou similaire est le moyen le plus efficace.

;WITH CTE AS
(
SELECT TOP 1000 *
FROM [mytab]
ORDER BY a1
)
DELETE FROM CTE
Martin Smith
la source
13
Pour ceux qui se demandent pourquoi vous ne pouvez pas le faire DELETE TOP (1000) FROM table ORDER BY column, lisez ceci : "Les lignes référencées dans l'expression TOP utilisée avec INSERT, UPDATE, MERGE ou DELETE ne sont pas organisées dans aucun ordre."
Nick Chammas
3
@Magnus oui. Pas 2000 cependant. Il serait peut-être possible d'utiliser une table dérivée en 2000. Je n'ai pas d'instance à tester.
Martin Smith
2
J'avais fait une manière légèrement différente (bien que je pense que le CTE pourrait être plus agréable à regarder): SUPPRIMER T1 DE (SELECT TOP 1000 * FROM [MYTAB] ORDER BY A1) T1;
Abacus
4
@Liam - juste parce que s'il y a une déclaration précédente avant le CTE, cela doit être terminé par un point-virgule, donc l'ajouter au WITHdébut de la liste prévient les plaintes des personnes qui ne l'ont pas fait.
Martin Smith
86

Peut être préférable pour sql2005 + à utiliser:

DELETE TOP (1000)
FROM [MyTab]
WHERE YourConditions

Pour Sql2000:

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

MAIS

Si vous souhaitez supprimer un sous-ensemble spécifique de lignes au lieu d'un sous-ensemble arbitraire, vous devez spécifier explicitement l'ordre de la sous-requête:

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

Merci à tp @gbn d'avoir mentionné et demandé la réponse la plus claire et la plus exacte.

Oleg Dok
la source
3
@gbn Peut-être inutile pour vous, mais c'est exactement ce que demande la question.
Joachim Isaksson
1
@Joachim Isaksson: allez lire sur TOP puis revenez. Il n'y a pas de TOP sans ORDER BY dans les ensembles. Sinon, allez me trouver une référence canonique qui me prouve mal ... Pour vous éviter de chercher, sqlblog.com/blogs/alexander_kuznetsov/archive/2009/05/20/… et blogs.technet.com/b/wardpond/archive /
2007/07/19
1
@gbn Aucune condition concernant les lignes à supprimer, donc ORDER BY dans la sous-requête est inutile
Oleg Dok
1
@gbn Avez-vous mentionné WHERE dans la sous-requête - Je filtre 1000 lignes arbitraires à l'intérieur des critères choisis et je les supprime ensuite. Scénario valide? Oui. Si j'ajoute ORDER BY NEWID () ou quoi que ce soit cela ne change rien - je supprime toujours 1000 lignes filtrées par critères choisis
Oleg Dok
8
@gbn Si vous recherchez une utilisation valide de TOP sans ORDER BY: ce qui m'a amené ici, c'est que je dois supprimer toutes les lignes correspondant à certains critères mais, pour des raisons de performances, je ne veux pas qu'il supprime plus de 10000 lignes à la fois. Je ne me soucie pas des lignes qu'il supprime, car je vais exécuter la commande à nouveau à un certain intervalle jusqu'à ce que toutes ces lignes aient disparu.
Richiban
6
delete from [mytab]
where [mytab].primarykeyid in
(
select top 1000 primarykeyid
from [mytab]
)
Jason Dam
la source
4
Inutile: TOP sans ORDER BY donne des lignes arbitraires
gbn
4
@gbn Peut-être inutile pour vous, mais c'est exactement ce que demande la question.
Joachim Isaksson
3
@gbn Je n'ai pas prétendu qu'il existe un ordre de tri par défaut ou que la requête est même utile de quelque manière que ce soit, je viens de vous rappeler que la question n'en demandait pas, alors sur quoi suggéreriez-vous de commander?
Joachim Isaksson
2
@gbn Je ne sais pas pourquoi vous êtes si hostile à tout le monde sur quelque chose qui est un point de départ. Je ne prétends pas que ma réponse est la fin, c'est simplement une suggestion pour aider quelqu'un. Je pense que l'importance réside dans les clés qui reviennent de la sous-requête ici.
Jason Dam
2
C'est peut-être tout ce que le demandeur recherche. Je voudrais simplement ajouter une note pour les autres lecteurs pour souligner que les lignes supprimées par une telle déclaration ne sont pas garanties d'être dans n'importe quel ordre.
Nick Chammas
3
SET ROWCOUNT 1000;

DELETE FROM [MyTable] WHERE .....
Joe Bourne
la source
2
Lorsqu'il s'agit de seulement 1000 lignes, est-ce vraiment important? S'il s'agissait de 100 000 000 lignes, vos points pourraient être valides, mais pour seulement 1 000 lignes, c'est de loin la solution la plus simple proposée à ce jour pour SQL 2008.
Joe Bourne
1

C'est rapide. Essayez-le:

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

Remplacer YourTABLEpar nom de table, XXpar un nombre, par exemple 1000, pkest le nom du champ de clé primaire de votre table.

Hamed elahi
la source
Vous créez effectivement deux tables à partir d'une seule, puis supprimez l'endroit où elles sont jointes. Cela fonctionne bien lorsque vous souhaitez supprimer les enregistrements les plus anciens (ou les plus récents) d'une table, car vous pouvez les trier par ordre croissant. Ce t-sql est accepté par Microsoft (et c'est rapide).
Tequila