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  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,585评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,923评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,314评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,346评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,718评论 3 291
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,828评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,020评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,758评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,486评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,722评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,196评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,546评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,211评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,132评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,916评论 0 200
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,904评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,758评论 2 274

推荐阅读更多精彩内容