Blog Post

You can’t DELETE TOP (x) with an ORDER BY

,

Did you know you can’t do this?

DELETE TOP (10)
FROM SalesOrderDetail
ORDER BY SalesOrderID DESC;

Msg 156, Level 15, State 1, Line 8

Incorrect syntax near the keyword ‘ORDER’.

I didn’t. Until I tried it anyway. Turns out, it says so right in the limitations section of BOL. Fortunately, that same section does have a recommendation on how to move forward.

If you need to use TOP to delete rows in a meaningful chronological order, you must use TOP together with an ORDER BY clause in a subselect statement.

Here is my version of the example they mentioned.

DELETE FROM SalesOrderDetail
WHERE SalesOrderDetailID IN  
   (SELECT TOP 10 SalesOrderDetailID
    FROM SalesOrderDetail
    ORDER BY SalesOrderID DESC);  
GO

And this works fine. But I remembered that you can update (and probably delete) from a CTE.

Well, I hadn’t tried it out before, so let’s give it a shot.

WITH MyCTE AS (
SELECT TOP (10) * 
FROM SalesOrderDetail
ORDER BY SalesOrderID DESC)
DELETE FROM MyCTE;

Well, the code is shorter. And it does work! So how about performance? Well, I checked the IO, and much like with the UPDATE it uses about half the IO (which when you look at the extra join in the subquery kind of makes sense). I ran both pieces of code 50 times and the subquery runs at about 62ms while the CTE runs at 48ms. Not a big difference, but these are pretty well indexed and very small. I’m going to go with the CTE as the better version.

Rate

★ ★ ★ ★ ★ ★ ★ ★ ★ ★

You rated this post out of 5. Change rating

Share

Share

Rate

★ ★ ★ ★ ★ ★ ★ ★ ★ ★

You rated this post out of 5. Change rating