Hey guys,
Good morning!

Today I will show you how to update or delete a fixed number of records from a table, which can be used to manipulate the table's data without locking it for a long time during query execution.

Generation of a simple base

I will demonstrate how to create the test base that we will use in this post

IF (OBJECT_ID('tempdb..#Teste') IS NOT NULL) DROP TABLE #Teste
CREATE TABLE #Teste (
    Linha INT IDENTITY(1, 1),
    Valor FLOAT,
    Processado BIT DEFAULT 0
)

INSERT INTO #Teste(Valor)
SELECT 125.99

INSERT INTO #Teste(Valor)
SELECT 457.64

INSERT INTO #Teste(Valor)
SELECT 124.77

INSERT INTO #Teste(Valor)
SELECT 3687.48

INSERT INTO #Teste(Valor)
SELECT 14.47

INSERT INTO #Teste(Valor)
SELECT 758.51

INSERT INTO #Teste(Valor)
SELECT 288.05

UPDATE TOP

Many people don't know, but the UPDATE statement supports the use of TOP to delimit the number of records to be updated:

UPDATE TOP (1) #Teste
SET Processado = 1

SQL Server - Update TOP 1
SQL Server - Update TOP 1

Although very simple, this command can end up tricking you. This happens because when you use a TOP command without using ORDER BY, the result is not deterministic. Every time you use a TOP, you must use an ORDER BY to indicate to the database how you will order the results and then filter using the TOP. Even if the table has a clustered index, this does not guarantee that the data will be ordered using the clustered index or with the RowID in the case of HEAP tables.

Although UPDATE supports TOP, it does not support ORDER BY. To resolve this situation, we can perform the same update in this way:

UPDATE A 
SET Processado = 1
FROM #Teste A
JOIN (
    SELECT TOP 2 *
    FROM #Teste WITH(NOLOCK)
    ORDER BY Linha DESC
) B ON B.Linha = A.Linha

Or it can be done with CTE (Common Table Expressions), which is a more elegant and efficient way:

;WITH CTE AS 
( 
    SELECT TOP 2 *
    FROM #Teste	WITH(NOLOCK)
    ORDER BY Linha DESC
) 
UPDATE CTE 
SET Processado = 1

Result:

SQL Server - Update TOP 1 _2
SQL Server - Update TOP 1 _2

Comparing the execution plan:

SQL Server - Update TOP 1 Execution Plan
SQL Server - Update TOP 1 Execution Plan

SQL Server - Update TOP 1 Execution Plan 2
SQL Server - Update TOP 1 Execution Plan 2

As indicated above, the solution using CTE is more elegant and performant, running in less time and consuming less disk and CPU

DELETE TOP

Just as we use in UPDATE, we can use TOP in DELETE itself, running the risk of deleting random records and we can also use ORDER BY, both JOIN in update and CTE to filter and limit the records that will be removed:

-- Apagando o primeiro registro (não há garantias de ser o primeiro registro)
DELETE TOP(1)
FROM #Teste A

-- Apagando o último registro utilizando JOIN
DELETE A FROM #Teste A
JOIN (
    SELECT TOP 1 * 
    FROM #Teste WITH(NOLOCK) 
    ORDER BY Linha DESC
) B ON B.Linha = A.Linha

-- Apagando o último registro utilizando CTE
;WITH CTE AS 
( 
    SELECT TOP 1 * 
    FROM #Teste WITH(NOLOCK) 
    ORDER BY Linha DESC
) 
DELETE CTE

Example:

SQL Server - Delete TOP 1_3
SQL Server - Delete TOP 1_3

That's it, folks!
A hug and see you in the next post.