DELETE (Transact-SQL)
Removes one or more rows from a table or view in SQL Server 2008.
[ WITH common_table_expression [ ,...n ] ]
DELETE
[ TOP (expression ) [ PERCENT ] ]
[ FROM ]
{ { table_alias
| <object>
| rowset_function_limited
[ WITH (table_hint_limited [ ...n ] ) ] }
| @table_variable
}
[ OUTPUT Clause ]
[ FROMtable_source [ ,...n ] ]
[ WHERE { search_condition
| { [ CURRENT OF
{ { [ GLOBAL ] cursor_name }
| cursor_variable_name
}
]
}
}
]
[ OPTION (Query Hint [ ,...n ] ) ]
[; ]
<object> ::=
{
[ server_name.database_name.schema_name.
| database_name. [ schema_name ] .
| schema_name.
]
table_or_view_name
}
To delete all the rows in a table, use TRUNCATE TABLE. TRUNCATE TABLE is faster than DELETE and uses fewer system and transaction log resources.
Use the @@ROWCOUNT function to return the number of deleted rows to the client application. For more information, see @@ROWCOUNT (Transact-SQL).
You can implement error handling for the DELETE statement by specifying the statement in a TRY…CATCH construct. For more information, see Using TRY...CATCH in Transact-SQL.
The DELETE statement may fail if it violates a trigger or tries to remove a row referenced by data in another table with a FOREIGN KEY constraint. If the DELETE removes multiple rows, and any one of the removed rows violates a trigger or constraint, the statement is canceled, an error is returned, and no rows are removed.
When a DELETE statement encounters an arithmetic error (overflow, divide by zero, or a domain error) occurring during expression evaluation, the Database Engine handles these errors as if SET ARITHABORT is set ON. The rest of the batch is canceled, and an error message is returned.
DELETE can be used in the body of a user-defined function if the object modified is a table variable.
When you delete a row that contains a FILESTREAM column, you also delete its underlying file system files. The underlying files are removed by the FILESTREAM garbage collector. For more information, see Managing FILESTREAM Data by Using Transact-SQL.
The FROM clause cannot be specified in a DELETE statement that references, either directly or indirectly, a view with an INSTEAD OF trigger defined on it. For more information about INSTEAD OF triggers, see CREATE TRIGGER (Transact-SQL).
When TOP is used with DELETE, the referenced rows are not arranged in any order and the ORDER BY clause can not be directly specified in this statement. 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. See the Examples section that follows in this topic.
TOP cannot be used in a DELETE statement against partitioned views.
The setting of the SET ROWCOUNT option is ignored for DELETE statements against remote tables and local and remote partitioned views.
When rows are deleted from a heap the Database Engine may use row or page locking for the operation. As a result, the pages made empty by the delete operation remain allocated to the heap. When empty pages are not deallocated, the associated space cannot be reused by other objects in the database. To delete rows in a heap and deallocate pages, use one of the following methods.
Specify the TABLOCK hint in the DELETE statement. Using the TABLOCK hint causes the delete operation to take a shared lock on the table instead of a row or page lock. This allows the pages to be deallocated. For more information about the TABLOCK hint, see Table Hints (Transact-SQL).
Use TRUNCATE TABLE if all rows are to be deleted from the table.
Create a clustered index on the heap before deleting the rows. You can drop the clustered index after the rows are deleted. This method is more time consuming than the previous methods and uses more temporary resources.
For more information about locking, see Locking in the Database Engine.
DELETE permissions are required on the target table. SELECT permissions are also required if the statement contains a WHERE clause.
DELETE permissions default to members of the sysadmin fixed server role, the db_owner and db_datawriter fixed database roles, and the table owner. Members of the sysadmin, db_owner, and the db_securityadmin roles, and the table owner can transfer permissions to other users.
Category | Featured syntax elements |
|---|---|
DELETE | |
WHERE clause • TOP • FROM clause and subqueries • cursor • WITH common table expression | |
Views • table variables | |
Linked server • OPENQUERY rowset function • OPENDATASOURCE rowset function | |
Overriding the default behavior of the query optimizer by using hints | Table hints |
OUTPUT clause | |
Using DELETE in Other Statements | Stored Procedure • MERGE |
Examples in this section demonstrate the basic functionality of the DELETE statement using the minimum required syntax.
The following example deletes all rows from the SalesPersonQuotaHistory table because a WHERE clause is not used to limit the number of rows deleted.
USE AdventureWorks; GO DELETE FROM Sales.SalesPersonQuotaHistory; GO
Examples in this section demonstrate ways to limit the number of rows deleted.
A. Using the WHERE clause to limit rows
The following example deletes all rows from the ProductCostHistory table in which the value in the StandardCost column is more than 1000.00.
USE AdventureWorks; GO DELETE FROM Production.ProductCostHistory WHERE StandardCost > 1000.00; GO
B. Using the TOP clause
You can use the TOP clause to limit the number of rows that are deleted in a DELETE statement. When a TOP (n) clause is used with DELETE, the delete operation is performed on a random selection of n number of rows.
The following example deletes 2.5 percent of the rows (27 rows) in the ProductInventory table.
USE AdventureWorks; GO DELETE TOP (2.5) PERCENT FROM Production.ProductInventory; GO
The following example deletes 20 random rows from the PurchaseOrderDetail table that have due dates that are earlier than July 1, 2002.
USE AdventureWorks; GO DELETE TOP (20) FROM Purchasing.PurchaseOrderDetail WHERE DueDate < '20020701'; GO
If you have to use TOP to delete rows in a meaningful chronological order, you must use TOP together with ORDER BY in a subselect statement. The following example deletes the 10 rows of the PurchaseOrderDetail table that have the earliest due dates. To ensure that only 10 rows are deleted, the column specified in the subselect statement (PurchaseOrderID) is the primary key of the table. Using a nonkey column in the subselect statement may result in the deletion of more than 10 rows if the specified column contains duplicate values.
USE AdventureWorks;
GO
DELETE FROM Purchasing.PurchaseOrderDetail
WHERE PurchaseOrderDetailID IN
(SELECT TOP 10 PurchaseOrderDetailID
FROM Purchasing.PurchaseOrderDetail
ORDER BY DueDate ASC);
GO
C. Using a cursor to delete the current row
The following example deletes a single row from the EmployeePayHistory table using a cursor named complex_cursor. The delete operation affects only the single row currently fetched from the cursor.
USE AdventureWorks;
GO
DECLARE complex_cursor CURSOR FOR
SELECT a.EmployeeID
FROM HumanResources.EmployeePayHistory AS a
WHERE RateChangeDate <>
(SELECT MAX(RateChangeDate)
FROM HumanResources.EmployeePayHistory AS b
WHERE a.EmployeeID = b.EmployeeID) ;
OPEN complex_cursor;
FETCH FROM complex_cursor;
DELETE FROM HumanResources.EmployeePayHistory
WHERE CURRENT OF complex_cursor;
CLOSE complex_cursor;
DEALLOCATE complex_cursor;
GO
D. Using a subquery and using the Transact-SQL FROM extension
The following example shows the Transact-SQL extension used to delete records from a base table that is based on a join or correlated subquery. The first DELETE statement shows the ISO-compatible subquery solution, and the second DELETE statement shows the Transact-SQL extension. Both queries remove rows from the SalesPersonQuotaHistory table based on the year-to-date sales stored in the SalesPerson table.
-- SQL-2003 Standard subquery
USE AdventureWorks;
GO
DELETE FROM Sales.SalesPersonQuotaHistory
WHERE SalesPersonID IN
(SELECT SalesPersonID
FROM Sales.SalesPerson
WHERE SalesYTD > 2500000.00);
GO
-- Transact-SQL extension
USE AdventureWorks;
GO
DELETE FROM Sales.SalesPersonQuotaHistory
FROM Sales.SalesPersonQuotaHistory AS spqh
INNER JOIN Sales.SalesPerson AS sp
ON spqh.SalesPersonID = sp.SalesPersonID
WHERE sp.SalesYTD > 2500000.00;
GO
E. Using a common table expression
The following example deletes only the rows returned by the common table expression.
Examples in this section demonstrate how to delete rows into a remote target table by using a linked server or a rowset function to reference the remote table.
Examples in this section demonstrate how to use table hints and query hints to temporarily override the default behavior of the query optimizer when processing the DELETE statement.
Caution |
|---|
Because the SQL Server query optimizer typically selects the best execution plan for a query, we recommend that hints be used only as a last resort by experienced developers and database administrators. |
The following example specified the table hint READPAST. When READPAST is specified, both row-level and page-level locks are skipped, which causes the Database Engine to not read rows and pages that are locked by other transactions. For more information, see Table Hints (Transact-SQL).
USE AdventureWorks; GO DELETE TOP(1) dbo.DatabaseLog WITH (READPAST) OUTPUT deleted.* WHERE DatabaseLogID = 7; GO
Examples in this section demonstrate how to use the OUTPUT Clause to return information from, or expressions based on, each row affected by an DELETE statement. These results can be returned to the processing application for use in such things as confirmation messages, archiving, and other such application requirements.
A. Using DELETE with the OUTPUT clause
The following example shows how to save the results of a DELETE statement into a table variable.
USE AdventureWorks; GO DELETE Sales.ShoppingCartItem OUTPUT DELETED.* WHERE ShoppingCartID = 20621; --Verify all rows in the table that match the WHERE clause have been deleted. SELECT COUNT(*) AS [Rows in Table] FROM Sales.ShoppingCartItem WHERE ShoppingCartID = 20621; GO
B. Using OUTPUT with from_table_name in a DELETE statement
The following example deletes rows in the ProductProductPhoto table based on search criteria defined in the FROM clause of the DELETE statement. The OUTPUT clause returns columns from the table being deleted, DELETED.ProductID, DELETED.ProductPhotoID, and columns from the Product table. This is used in the FROM clause to specify the rows to delete.
USE AdventureWorks;
GO
DECLARE @MyTableVar table (
ProductID int NOT NULL,
ProductName nvarchar(50)NOT NULL,
ProductModelID int NOT NULL,
PhotoID int NOT NULL);
DELETE Production.ProductProductPhoto
OUTPUT DELETED.ProductID,
p.Name,
p.ProductModelID,
DELETED.ProductPhotoID
INTO @MyTableVar
FROM Production.ProductProductPhoto AS ph
JOIN Production.Product as p
ON ph.ProductID = p.ProductID
WHERE p.ProductModelID BETWEEN 120 and 130;
--Display the results of the table variable.
SELECT ProductID, ProductName, ProductModelID, PhotoID
FROM @MyTableVar
ORDER BY ProductModelID;
GO
