SQL Server删除表中的数据

使用 DELETE 删除行

DELETE 语句可删除表或视图中的一行或多行。DELETE 语法的简化形式为:

DELETE table_or_view
FROM table_sources
WHERE search_condition
  • table_or_view 指定要从中删除行的表或视图。table_or_view 中所有符合 WHERE 搜索条件的行都将被删除。如果没有指定 WHERE 子句,将删除 table_or_view 中的所有行。
  • FROM 子句指定可由 WHERE 子句搜索条件中的谓词使用的其他表或视图及联接条件(以关联表为条件删除另一条的数据),以限定要从 table_or_view 中删除的行。不会从 FROM 子句指定的表中删除行,只从 table_or_view 指定的表中删除行。详见示例(3)。

锁定行为
  默认情况下,DELETE 语句始终在其修改的表上获取排他 (X) 锁并在事务完成之前持有该锁。 使用排他锁(X 锁)时,任何其他事务都无法修改数据;仅在使用 NOLOCK 提示或未提交读隔离级别时才会进行读取操作。
  从堆中删除行时,数据库引擎可以使用行锁定或页锁定进行操作。结果,删除操作导致的空页将继续分配给堆。未释放空页时,数据库中的其他对象将无法重用关联的空间。
  若要删除堆中的行并释放页,请使用下列方法之一。

  • 在 DELETE 语句中指定 TABLOCK 提示。使用 TABLOCK 提示会导致删除操作获取表的共享锁,而不是行锁或页锁。这将允许释放页。
  • 如果要从表中删除所有行,请使用 TRUNCATE TABLE。
  • 删除行之前,请对堆创建聚集索引。删除行之后,可以删除聚集索引。与先前的方法相比,此方法非常耗时,并且使用更多的临时资源。

日志记录行为
  DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一个项。

【示例】
(1)下面的示例从 SalesPersonQuotaHistory 表中删除所有行,因为该例未使用 WHERE 子句限制删除的行数。

DELETE FROM Sales.SalesPersonQuotaHistory

(2)下面的示例从 ProductCostHistory 表中删除 StandardCost 列的值大于 1000.00 的所有行。

DELETE FROM Production.ProductCostHistory WHERE StandardCost > 1000.00

(3)从 SalesPersonQuotaHistory 表中删除行,该表基于 SalesPerson 表中所存储的本年度迄今为止的销售业绩。第一条 DELETE 语句显示与 ISO 兼容的子查询解决方案,第二条 DELETE 语句显示 Transact-SQL 扩展插件。

-- SQL-2003 Standard subquery
DELETE FROM Sales.SalesPersonQuotaHistory 
WHERE BusinessEntityID IN 
    (SELECT BusinessEntityID 
     FROM Sales.SalesPerson 
     WHERE SalesYTD > 2500000.00);
-- Transact-SQL extension
DELETE FROM Sales.SalesPersonQuotaHistory 
FROM Sales.SalesPersonQuotaHistory AS spqh
INNER JOIN Sales.SalesPerson AS sp
ON spqh.BusinessEntityID = sp.BusinessEntityID
WHERE sp.SalesYTD > 2500000.00;

使用 TRUNCATE TABLE 删除所有行

若要删除表中的所有行,则 TRUNCATE TABLE 语句是一种快速、有效的方法。TRUNCATE TABLE 与不含 WHERE 子句的 DELETE 语句类似。但是,TRUNCATE TABLE 速度更快,并且使用更少的系统资源和事务日志资源。
  与 DELETE 语句相比,TRUNCATE TABLE 具有以下优点:

  • 所用的事务日志空间较少。
    DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一个项。TRUNCATE TABLE 通过释放用于存储表数据的数据页来删除数据,并且在事务日志中只记录页释放。
  • 使用的锁通常较少。
    当使用行锁执行 DELETE 语句时,将锁定表中各行以便删除。TRUNCATE TABLE 始终锁定表和页,而不是锁定各行。
  • 如无例外,在表中不会留有任何页。
    执行 DELETE 语句后,表仍会包含空页。尽管这些页会通过后台清除进程迅速释放。

下面的示例删除 JobCandidate 表中的所有数据。在 TRUNCATE TABLE 语句之前和之后使用 SELECT 语句来比较结果。

SELECT COUNT(*) AS BeforeTruncateCount 
FROM HumanResources.JobCandidate;
GO
TRUNCATE TABLE HumanResources.JobCandidate;
GO
SELECT COUNT(*) AS AfterTruncateCount 
FROM HumanResources.JobCandidate;
GO

删除结果集中的行

ADO、OLE DB 和 ODBC API 支持从结果集中删除应用程序所在的当前行。应用程序执行某个语句,然后从结果集中提取行。应用程序提取行后,就可以使用以下函数或方法删除该行:

  • ADO 应用程序使用 Recordset 对象的 Delete 方法。
  • OLE DB 应用程序使用 IRowsetChange 接口的** DeleteRows **方法。
  • ODBC 应用程序使用带 SQL_DELETE 选项的 SQLSetPos 函数。
  • DB-library 应用程序使用 **dbcursor **执行 **CRS_DELETE **操作。

Transact-SQL 脚本、存储过程和触发器可以使用DELETE语句中的 WHERE CURRENT OF子句来删除它们当前所在的游标行。以下示例使用名为complex_cursor的游标从 EmployeePayHistory 表中删除一行。DELETE 只影响当前从游标中提取的一行。

DECLARE complex_cursor CURSOR FOR
    SELECT a.BusinessEntityID
    FROM HumanResources.EmployeePayHistory AS a
    WHERE RateChangeDate <> 
         (SELECT MAX(RateChangeDate)
          FROM HumanResources.EmployeePayHistory AS b
          WHERE a.BusinessEntityID = b.BusinessEntityID) ;
OPEN complex_cursor;
FETCH FROM complex_cursor;
DELETE FROM HumanResources.EmployeePayHistory
WHERE CURRENT OF complex_cursor;
CLOSE complex_cursor;
DEALLOCATE complex_cursor;
GO

使用 TOP 限制删除的行

可以使用 TOP 子句限制 DELETE 语句中删除的行数。当 TOP (n) 子句与 DELETE 一起使用时,将针对随机选择的第 n 行执行删除操作。
  例如,下面的语句从 PurchaseOrderDetail 表中删除了其到期日期早于 2002 年 7 月 1 日的 20 个随机行

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

在将 TOP 与 DELETE 结合使用时,被引用行不按任何顺序排列,不能直接在此语句中指定 ORDER BY 子句。 如果需要使用 TOP 来删除按有意义的时间顺序排列的行,您必须同时在嵌套 select 语句中使用 TOP 和 ORDER BY 子句。
  下面的查询从 PurchaseOrderDetail 表中删除了其到期日期最早的 10 行。为了确保仅删除 10 行,嵌套 Select 语句 (PurchaseOrderID) 中指定的列将成为表的主键。如果指定列包含重复的值,则在嵌套 Select 语句中使用非键列可能会导致删除的行超过 10 个。

DELETE FROM Purchasing.PurchaseOrderDetail
WHERE PurchaseOrderDetailID IN
   (SELECT TOP 10 PurchaseOrderDetailID 
    FROM Purchasing.PurchaseOrderDetail 
    ORDER BY DueDate ASC);
GO

DELETE (Transact-SQL)

-- Syntax for SQL Server and Azure SQL Database  
  
[ 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> ]  
    [ FROM table_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   
}  
  • TOP (expression) [ PERCENT ]
    指定将要删除的任意行数或任意行的百分比。 expression 可以是行数或行的百分比。
  • server_name:表或视图所在的链接服务器的名称。
  • database_name:数据库的名称。
  • schema_name:表或视图所属架构的名称。
  • table_or view_name:要从中删除行的表或视图的名称。
  • <OUTPUT_Clause>:OUTPUT子句
  • table_source:指定可由 WHERE 子句搜索条件中的谓词使用的其他表或视图及联接条件(以关联表为条件删除另一条的数据),以限定要从 table_or_view 中删除的行。不会从 FROM 子句指定的表中删除行,只从 table_or_view 指定的表中删除行。

【示例】
  一些基本的示例在上面已经演示过,比如T-SQL扩展插件写法(DELETE table_or_view FROM table_sources)、从游标中删除结果集中的行、使用Top限制删除行等。下面示例使用OUTPUT子句捕获 DELETE 语句的结果。

A. 使用带有 OUTPUT 子句的 DELETE

DELETE Sales.ShoppingCartItem  
OUTPUT DELETED.*   
WHERE ShoppingCartID = 20621;  

B. 在 DELETE 语句中同时使用 OUTPUT 与 <from_table_name>
  从 ProductProductPhoto表中删除行,该表基于Product表中所存储的ProductModelID。OUTPUT 子句返回所删除表中的列( DELETED.ProductID、 DELETED.ProductPhotoID)以及 Product 表中的列。

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;  
 
GO  
    原文作者:zoyoto
    原文地址: https://www.jianshu.com/p/ec5738fd443f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞