Hello people,
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 table data without locking it for a long time while executing queries.
Generation of a simple base
I will demonstrate how to create the test base that we will use in this post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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
A lot of people don't know, but the UPDATE statement supports using TOP to delimit the amount of records to update:
1 2 |
UPDATE TOP (1) #Teste SET Processado = 1 |
Although quite simple, this command can end up fooling you. This is 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 tell the bank how to sort the results and then filter using the TOP. Even if the table has clustered index, this does not guarantee that the data will be sorted using the clustered index or with RowID for HEAP tables.
Although UPDATE supports TOP, it does not support ORDER BY. To resolve this situation, we can perform this same update as follows:
1 2 3 4 5 6 7 8 |
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:
1 2 3 4 5 6 7 8 |
;WITH CTE AS ( SELECT TOP 2 * FROM #Teste WITH(NOLOCK) ORDER BY Linha DESC ) UPDATE CTE SET Processado = 1 |
As indicated above, the solution using CTE is more elegant and performative, running faster and consuming less disk and CPU.
DELETE TOP
As with UPDATE, we can use TOP on DELETE itself, at the risk of deleting random records, and we can use ORDER BY on both JOIN on update and CTE to filter and limit the records that will be removed:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
-- 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 |
That's it folks!
Regards and see you next post.
CTE (Common Table Expressions)…. great tip… saved me !!!