How to delete the top 1000 rows from a table using Sql Server 2008?
Asked Answered
P

10

150

I have a table in SQL Server. I would like to delete the top 1000 rows from it. However, I tried this, but I instead of just deleting the top 1000 rows it deleted all the rows in the table.

Here is the code:

delete from [mytab] 
select top 1000 
a1,a2,a3
from [mytab]
Penuchle answered 21/1, 2012 at 19:14 Comment(6)
You need an ORDER BY to make TOP meaningful: see @Martin Smith's answer which is the only one of five to have this. I despair sometimesBluhm
Do you want to delete any 1000 rows? Just randomly selected? Or, for example, the top 1000 oldest rows?Tussle
You deleted all the table because delete from [mytab] is one statement, and select top ... is another.Tussle
You don't need ordering for top, depends why you are doing TOP. If you need to remove 10 million rows and have 1 GB of log space available use Delete TOP(10000) From dbo.myTable (with your select clause) and keep running it till there are no more rows to delete. Who cares if its arbitrary. Sorting only slows the query.Ludwog
I realize that this is an ancient question (in SO years) but I do think that it is important that people consider the comments of @gbn. While his comments do not apply to my given situation (trying to delete blocks of records without causing LOCK issues but not really caring about the order in which they are deleted) they may very likely apply to YOUR situation. Make sure you consider them before blindly utilizing answers below that do not include an ORDER BY clause.Dative
You should also read up on SQL lock escalation as there are reasons not to delete more than 5000 rows at a time in a production system. technet.microsoft.com/en-us/library/ms184286(v=sql.105).aspxNoneffective
P
253

The code you tried is in fact two statements. A DELETE followed by a SELECT.

You don't define TOP as ordered by what.

For a specific ordering criteria deleting from a CTE or similar table expression is the most efficient way.

;WITH CTE AS
(
SELECT TOP 1000 *
FROM [mytab]
ORDER BY a1
)
DELETE FROM CTE
Predesignate answered 21/1, 2012 at 19:55 Comment(9)
For those wondering why you can't do DELETE TOP (1000) FROM table ORDER BY column, read this: "The rows referenced in the TOP expression used with INSERT, UPDATE, MERGE, or DELETE are not arranged in any order."Tussle
@Magnus yes. Not 2000 though. It might be possible to use a derived table in 2000. I haven't an instance around to test with.Predesignate
All you need to do is: SET ROWCOUNT 1000; DELETE FROM [MyTable] WHERE ..... thats what the ROWCOUNT function is for!Gyration
@Joe Using SET ROWCOUNT will not affect DELETE, INSERT, and UPDATE statements in a future release of SQL Server. Avoid using SET ROWCOUNT with DELETE, INSERT, and UPDATE statements in new development work, and plan to modify applications that currently use it.Predesignate
I had done a slightly different way (though I think the CTE might be nicer to look at): DELETE T1 FROM (SELECT TOP 1000 * FROM [MYTAB] ORDER BY A1) T1;Bouie
why the leading ;?Sestet
@Sestet - just because if there is any preceding statement before the CTE this needs to be terminated with a semicolon so appending it to the front of the WITH pre-empts complaints from people that haven't done that.Predesignate
If i have 2 million rows that and the query times out for even 200k, is there any way to make this query loop and perform the delete in chunks?Inositol
This solution is also faster than similar delete from table where id in (select top 1000 id from table order by a1). In my case with 50 million rows difference was 20% to 80%.Extenuation
B
134

May be better for sql2005+ to use:

DELETE TOP (1000)
FROM [MyTab]
WHERE YourConditions

For Sql2000:

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

BUT

If you want to delete specific subset of rows instead of arbitrary subset, you should explicitly specify order to subquery:

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

Thanks tp @gbn for mentioning and demanding the more clear and exact answer.

Berchtesgaden answered 21/1, 2012 at 19:27 Comment(9)
@Bluhm Maybe useless for you, but still that is exactly what the question is asking for.Sanctified
@Joachim Isaksson: go and read up about TOP then come back. There is no such thing as TOP without an ORDER BY in sets. Alternatively, go and find me a canonical reference that proves me wrong... To save you searching, sqlblog.com/blogs/alexander_kuznetsov/archive/2009/05/20/… and blogs.technet.com/b/wardpond/archive/2007/07/19/…Bluhm
@Bluhm No any conditions about WHICH rows to delete, so ORDER BY in subquery is uselessBerchtesgaden
@Bluhm Did you mention WHERE in subquery - I filter 1000 arbitrary rows inside choosen criteria and delete then. Valid scenario? Yes. If I add ORDER BY NEWID() or whatever it changes nothing - I still delete 1000 rows filtered by choosen criteriaBerchtesgaden
@Bluhm The question is: I have a table in SQL I would like to delete 1000 rows from it I tried this, But I deleted all table. Where do you see top word in the question. So, If it not stated than we need to delete top X from smth. so we assume that we should delete 1000 arbitrary rows. Sounds weird - agree, but valid scenario? - agree tooBerchtesgaden
@OLegDok: I see it in the question title: "delete top 1000 rows ..."Readus
@Bluhm In case you're looking for a valid use of TOP without ORDER BY: what brought me here is I need to delete all rows matching some criteria but, for performance reasons, I don't want it to delete more than 10,000 rows at a time. I don't care which rows it deletes, as I will run the command again at some interval until all such rows are gone.Irremeable
important: paranthesis after top is importantCardamom
Using TOP (X) with delete is absolutely a valid scenario and anyone who manages large databases should be aware of it for managing performance while deleting massive amounts of data with concurrent load. It is also the simplest way to script unordered deletes that can easily be changed from batched to non-batched form. Unordered deletes are valuable when you want to create the least amount of work on the database.Cotoneaster
P
34

As defined in the link below, you can delete in a straight forward manner

USE AdventureWorks2008R2;
GO
DELETE TOP (20) 
FROM Purchasing.PurchaseOrderDetail
WHERE DueDate < '20020701';
GO

http://technet.microsoft.com/en-us/library/ms175486(v=sql.105).aspx

Phosphorism answered 17/1, 2015 at 11:25 Comment(0)
J
8
delete from [mytab]
where [mytab].primarykeyid in
(
select top 1000 primarykeyid
from [mytab]
)
Jezreel answered 21/1, 2012 at 19:16 Comment(9)
Useless: TOP without an ORDER BY gives arbitrary rowsBluhm
@Bluhm Maybe useless for you, but still that is exactly what the question is asking for.Sanctified
@Joachim Isaksson: I'd downvote more if I could for arguing. Go and read up about TOP then come back. There is no such thing as TOP without an ORDER BY in sets. Alternatively, go and find me a canonical reference that proves me wrong... To save you searching, sqlblog.com/blogs/alexander_kuznetsov/archive/2009/05/20/… and blogs.technet.com/b/wardpond/archive/2007/07/19/…Bluhm
@Bluhm I did not claim that there is any default sort order or that the query is even in any way useful, I just reminded you that the question did not ask for one so what would you suggest ordering on?Sanctified
@Bluhm I don't know why you're so hostile to everyone over something that is a starting point. I do not claim that my answer is the end all, it is merely a suggestion to help someone out. I think the importance is the keys that are coming back from the sub query here.Jezreel
This may be all that the asker is looking for. I would just add a note for others reading to stress that the rows deleted by such a statement are not guaranteed to be in any order.Tussle
@Jason Dam: because of too many upvotes for incorrect answers. OP said "TOP". Top what? Quite simple.Bluhm
@Bluhm in my case, I am trying to purge a large subset of records from a bloated table and don't care WHAT ORDER they are deleted in, just as long as they meet the criteria, but I don't want to delete ALL of them at once to prevent LOCK problems. And NO, I cannot do the "copy records I want to keep to new table, then drop current table and finally rename new table to old name" routine. Try to be a little more open minded and a little less hostile.Dative
@gbn, HOWEVER, your point is a valid one that people should take into consideration. (Credit where credit is due, even if I disagree with delivery!)Dative
G
4
SET ROWCOUNT 1000;

DELETE FROM [MyTable] WHERE .....
Gyration answered 14/3, 2014 at 11:25 Comment(1)
When dealing with just 1000 rows, does it really matter?? If it was 100,000,000 rows then your points might be valid, but for just 1000 rows, this is by far the simplest solution proposed so far for SQL 2008.Gyration
C
3

It is fast. Try it:

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

Replace YourTABLE by table name, XX by a number, for example 1000, pk is the name of the primary key field of your table.

Cerebro answered 14/4, 2015 at 7:21 Comment(1)
You are effectively creating two tables from one, and then deleting where joined. It works well when you want to delete the oldest (or newest) records from a table, since you can sort them ascending first. This t-sql is accepted by Microsoft (and it's fast).Slim
T
2

No need to create CTE to fetch and delete as it will load the records in memory first and then perform the delete operation which might impact the performance.

All you need is simple delete top(n) based on your condition to remove the records from your table which is fast and efficient for non-partitioned table.

delete top(1000)
from [mytab] 
where 
 condition[1]
 condition[2]
 .
 .
 condition[n]
Thurber answered 1/8, 2023 at 11:45 Comment(0)
M
1

I agree with the Hamed elahi and Glorfindel.

My suggestion to add is you can delete and update using aliases

/* 
  given a table bi_customer_actions
  with a field bca_delete_flag of tinyint or bit
    and a field bca_add_date of datetime

  note: the *if 1=1* structure allows me to fold them and turn them on and off
 */
declare
        @Nrows int = 1000

if 1=1 /* testing the inner select */
begin
  select top (@Nrows) * 
    from bi_customer_actions
    where bca_delete_flag = 1
    order by bca_add_date
end

if 1=1 /* delete or update or select */
begin
  --select bca.*
  --update bca  set bca_delete_flag = 0
  delete bca
    from (
      select top (@Nrows) * 
        from bi_customer_actions
        where bca_delete_flag = 1
        order by bca_add_date
    ) as bca
end 
Mutism answered 29/10, 2020 at 20:13 Comment(0)
C
1

To enhance the accepted answer code, check out mine. The code will start by deleting 1000 rows from the table at a time, and then increase the batch size by 10% after each iteration. This way, the code will delete more rows as the table gets smaller and reduce the number of loops needed. The variable @count will still store the number of rows affected by each delete statement and the loop will stop when it becomes zero.

DECLARE @batch_size INT = 10000
DECLARE @count INT = 1
WHILE @count > 0
BEGIN
    ;WITH CTE AS
    (
    SELECT TOP (@batch_size) *
    FROM [mytab]
    ORDER BY a1
    )
    DELETE FROM CTE

    SET @count = @@ROWCOUNT

    -- Increase the batch size by 10% after each iteration
    SET @batch_size = @batch_size * 1.1
END
Carrier answered 5/4, 2023 at 17:0 Comment(0)
P
0

None of these solutions worked for me, instead I had to open MSSQL Management Studio, right-click on the database and select "Tasks > Shrink > Database".

I'm running SQL Server 2022, so maybe things have changed since most of these answers.

Potheen answered 26/1 at 10:17 Comment(1)
If shrink database worked for you, then you had a different question or problem than asked about here.Halloran

© 2022 - 2024 — McMap. All rights reserved.