SQL Server DML 操作语句完全指南

数据定义(DDL)决定数据库长什么样,而数据操作(DML)决定数据库每天在做什么。 对于绝大多数业务系统来说,真正运行最频繁的不是 CREATE TABLE,而是 INSERT、UPDATE、DELETE 等 DML 操作。

本文将系统介绍 SQL Server 中最常用的 DML(Data Manipulation Language,数据操作语言)语句,包括 INSERT、UPDATE、DELETE、MERGE、OUTPUT 的使用方法、典型业务场景、性能优化技巧以及生产环境中的注意事项。


一、什么是 DML?

DML(Data Manipulation Language)即数据操作语言 ,主要负责对表中的数据进行新增、修改、删除和合并

SQL Server 中最核心的 DML 语句包括:

  • INSERT:新增数据

  • UPDATE:修改数据

  • DELETE:删除数据

  • MERGE:同步、合并数据(UPSERT)

  • OUTPUT:返回受影响的数据

可以把数据库比作一本账本:

  • INSERT 就是在账本中新写一条记录;

  • UPDATE 是修改已有记录;

  • DELETE 是划掉记录;

  • MERGE 则像对照两本账本进行同步;

  • OUTPUT 则是操作时自动生成一份变更清单。


二、INSERT------新增数据

INSERT 用于向表中写入新数据。

基本语法

复制代码
INSERT INTO 表名 (列1, 列2, ...)
VALUES (值1, 值2, ...);

场景一:插入单条用户数据

复制代码
INSERT INTO Users
(
    UserName,
    Email,
    CreateTime
)
VALUES
(
    'Tom',
    'tom@test.com',
    GETDATE()
);

适用于:

  • 用户注册

  • 创建订单

  • 新增商品


场景二:一次插入多条数据

复制代码
INSERT INTO Users
(
    UserName,
    Email
)
VALUES
('Alice','alice@test.com'),
('Bob','bob@test.com'),
('Jack','jack@test.com');

SQL Server 2008 起支持这种写法。

相比循环 INSERT,效率明显更高。


场景三:从查询结果插入

例如归档历史订单。

复制代码
INSERT INTO OrderHistory
(
    OrderID,
    UserID,
    Amount
)
SELECT
    OrderID,
    UserID,
    Amount
FROM Orders
WHERE Status='Completed';

这种方式通常比程序循环导入快得多。


场景四:使用 DEFAULT

复制代码
INSERT INTO Users
(
    UserName,
    Status
)
VALUES
(
    'Jerry',
    DEFAULT
);

要求字段定义了默认值。

例如:

复制代码
Status INT DEFAULT 1

性能与注意事项

建议:

  • 指定列名,不建议使用 INSERT INTO Table VALUES(...)

  • 批量导入优先使用多值 INSERT、BCP、BULK INSERT

  • 大批量插入可考虑关闭非聚集索引后重建


三、UPDATE------修改数据

UPDATE 用于修改已有记录。

基本语法

复制代码
UPDATE 表名
SET 列=值
WHERE 条件;

场景一:修改用户手机号

复制代码
UPDATE Users
SET Phone='13800001111'
WHERE UserID=1001;

场景二:订单批量修改状态

复制代码
UPDATE Orders
SET Status='Completed'
WHERE PayStatus='Paid';

典型应用:

支付成功后更新订单状态。


场景三:基于 JOIN 更新

例如同步会员等级。

复制代码
UPDATE U
SET U.LevelName=L.LevelName
FROM Users U
INNER JOIN UserLevel L
ON U.LevelID=L.LevelID;

这种 UPDATE 是 SQL Server 非常实用的扩展。


UPDATE 注意事项

务必带 WHERE 条件。

建议先执行:

复制代码
SELECT *
FROM Orders
WHERE Status='Pending';

确认影响范围后再:

复制代码
UPDATE Orders
SET Status='Processing'
WHERE Status='Pending';

这是 DBA 最基本的操作规范。


四、DELETE------删除数据

DELETE 删除的是数据,而不是表。

基本语法

复制代码
DELETE
FROM 表名
WHERE 条件;

场景一:删除单个用户

复制代码
DELETE
FROM Users
WHERE UserID=1001;

场景二:删除测试数据

复制代码
DELETE
FROM Orders
WHERE UserID=-1;

很多开发环境都会保留这种测试账号。


场景三:删除过期日志

复制代码
DELETE
FROM SystemLog
WHERE CreateTime < DATEADD(MONTH,-6,GETDATE());

这是日志清理最常见的方式。


DELETE 与 TRUNCATE 的区别

对比项 DELETE TRUNCATE
删除方式 按行删除 整表快速清空
WHERE 支持 不支持
日志 较多 较少
Identity 不重置 重置
触发器 会触发 不触发 DELETE Trigger

一般来说:

  • 清空整张表 → TRUNCATE

  • 删除部分数据 → DELETE

如果存在外键引用,TRUNCATE 通常无法执行。


五、MERGE------同步数据(UPSERT)

MERGE 可以一次完成:

  • 存在则更新

  • 不存在则插入

  • 可选删除目标中多余数据

因此也称 UPSERT


基本语法

复制代码
MERGE Target AS T
USING Source AS S
ON T.ID=S.ID
WHEN MATCHED THEN
    UPDATE ...
WHEN NOT MATCHED THEN
    INSERT ...;

场景一:同步用户信息

复制代码
MERGE Users AS T
USING TempUsers AS S
ON T.UserID=S.UserID

WHEN MATCHED THEN
UPDATE SET
    T.UserName=S.UserName,
    T.Email=S.Email

WHEN NOT MATCHED THEN
INSERT
(
    UserID,
    UserName,
    Email
)
VALUES
(
    S.UserID,
    S.UserName,
    S.Email
);

非常适合:

  • 数据同步

  • ETL

  • 数据仓库


场景二:同步商品库存

每天 ERP 导入库存:

复制代码
MERGE ProductStock AS T
USING ImportStock AS S
ON T.ProductID=S.ProductID

WHEN MATCHED THEN
UPDATE SET
Stock=S.Stock

WHEN NOT MATCHED THEN
INSERT(ProductID,Stock)
VALUES(S.ProductID,S.Stock);

MERGE 注意事项

SQL Server 多个版本曾修复过 MERGE 的边界 Bug,生产环境建议:

  • 保持最新累计更新(CU)

  • 并发较高场景可考虑拆分为 UPDATE+INSERT 两步实现

  • 大批量同步建议结合事务与索引优化


六、OUTPUT------获取受影响的数据

很多人不知道,SQL Server 可以直接返回本次 DML 操作的数据。

INSERT OUTPUT

复制代码
INSERT INTO Users
(
    UserName
)
OUTPUT INSERTED.UserID,
       INSERTED.UserName
VALUES
(
    'Lucy'
);

返回:

复制代码
UserID
UserName

无需再次查询。


UPDATE OUTPUT

复制代码
UPDATE Orders
SET Amount=Amount+100

OUTPUT
DELETED.Amount AS OldAmount,
INSERTED.Amount AS NewAmount

WHERE OrderID=10;

其中:

  • INSERTED:修改后数据

  • DELETED:修改前数据

非常适合:

  • 审计日志

  • 数据追踪

  • 数据回滚记录


DELETE OUTPUT

复制代码
DELETE
FROM Users

OUTPUT
DELETED.*

WHERE UserID=100;

删除前的数据可以直接保存到日志表。


七、事务管理:保证数据一致性

多个 DML 通常需要作为一个整体执行。

复制代码
BEGIN TRAN;

UPDATE Account
SET Balance=Balance-100
WHERE UserID=1;

UPDATE Account
SET Balance=Balance+100
WHERE UserID=2;

COMMIT;

发生异常:

复制代码
ROLLBACK;

最佳实践:

  • 一个业务一个事务

  • 事务尽量短

  • 不要在事务中等待用户输入

  • 及时 COMMIT 或 ROLLBACK


八、DML 最佳实践

1、先 SELECT,再 UPDATE/DELETE

复制代码
SELECT *
FROM Orders
WHERE Status='Pending';

确认无误后再执行修改。


2、避免锁表

对于百万级数据:

不要:

复制代码
DELETE FROM Orders;

建议:

复制代码
WHILE 1=1
BEGIN
    DELETE TOP (5000)
    FROM Orders
    WHERE CreateTime<'2023-01-01';

    IF @@ROWCOUNT=0 BREAK;
END

批量删除能够有效减少锁竞争与事务日志压力。


3、合理建立索引

WHERE 条件字段建议建立索引。

否则:

UPDATE、DELETE 很容易全表扫描。


4、批量导入优化

对于海量数据:

  • 使用 BULK INSERT

  • 使用 SqlBulkCopy(.NET)

  • 分批提交事务

  • 导入完成后更新统计信息


九、常见陷阱

1、忘记 WHERE

复制代码
UPDATE Users
SET Status=0;

整个用户表都会被修改。

这是数据库事故中最常见的问题之一。


2、隐式类型转换

例如:

复制代码
WHERE UserID='100'

如果 UserID 为 INT,SQL Server 可能发生隐式转换,影响索引使用,导致性能下降。

建议保持参数类型与字段类型一致。


3、NULL 判断错误

错误写法:

复制代码
WHERE Email=NULL

正确写法:

复制代码
WHERE Email IS NULL

同样:

复制代码
IS NOT NULL

而不是:

复制代码
!= NULL

4、外键约束

例如:

Orders

引用

Users

删除用户:

复制代码
DELETE FROM Users
WHERE UserID=1;

如果订单仍存在,将提示外键冲突。

应:

  • 先删除子表

  • 或配置级联删除(CASCADE)

  • 或重新设计业务逻辑


十、综合案例:订单同步与归档

假设每天凌晨需要同步外部订单,并归档已完成订单。

第一步:同步新增和更新订单

复制代码
MERGE Orders AS T
USING ImportOrders AS S
ON T.OrderID = S.OrderID
WHEN MATCHED THEN
    UPDATE SET
        T.Amount = S.Amount,
        T.Status = S.Status
WHEN NOT MATCHED THEN
    INSERT (OrderID, UserID, Amount, Status)
    VALUES (S.OrderID, S.UserID, S.Amount, S.Status);

第二步:记录变更日志

复制代码
UPDATE Orders
SET Status = 'Archived'
OUTPUT
    INSERTED.OrderID,
    DELETED.Status,
    INSERTED.Status,
    GETDATE()
INTO OrderChangeLog
WHERE Status = 'Completed';

第三步:归档历史数据

复制代码
INSERT INTO OrderHistory
SELECT *
FROM Orders
WHERE Status='Archived';

DELETE
FROM Orders
WHERE Status='Archived';

整个流程建议放入事务中执行,并结合适当索引,确保同步、日志记录和归档的一致性。


十一、SQL Server 版本差异

不同版本对 DML 能力持续增强:

  • SQL Server 2008 :支持多行 VALUES 插入、MERGE 语句。

  • SQL Server 2012 :增强 OFFSET/FETCH 等分页能力,便于与 DML 配合处理批量数据。

  • SQL Server 2016+ :在 JSON、Temporal Table 等特性上有明显增强,可配合 OUTPUT 构建审计方案,同时对批量操作和查询优化器进行了持续改进。

  • SQL Server 2019/2022 :智能查询处理(Intelligent Query Processing)进一步优化部分 DML 相关执行计划,但 MERGE 在高并发场景仍建议充分测试后再投入生产。


总结

DML 是数据库开发中使用频率最高的一组 SQL 语句,也是最容易因为误操作而引发生产事故的部分。掌握 INSERT、UPDATE、DELETE、MERGE 与 OUTPUT 的正确使用方式,不仅能够完成日常的数据维护工作,更能编写出安全、高效、易维护的数据处理程序。

最后,牢记几条经验法则:

  • 任何 UPDATE、DELETE 都应先用 SELECT 验证影响范围。

  • 涉及多步修改时使用事务,确保数据一致性。

  • 批量操作采用分批提交,减少锁竞争和事务日志压力。

  • 充分利用 OUTPUT 实现数据审计与变更追踪。

  • MERGE 虽然功能强大,但在高并发业务中应结合版本特性和实际测试谨慎使用。

相关推荐
Irene19911 小时前
Oracle 连接避坑指南:环境+配置+账号
数据库·oracle
不在逃避q1 小时前
一步一步学习使用LiveBindings()TListView进阶使用(),打造天气预报程序
服务器·数据库·学习
2401_873479401 小时前
IPv6支持不足怎么办?用双栈兼容IP离线库实现平滑过渡
数据库·网络协议·tcp/ip·ip
AI多Agent协作实战派1 小时前
AI多Agent协作系统实战(二十八):顶栏统一战争——从1个页面异常到31个页面全量对齐
数据库·人工智能·uni-app
吴声子夜歌1 小时前
MongoDB 8.0——可视化管理工具
数据库·mongodb
zdl6862 小时前
EasyMarkets:“芯片波动考验科技估值”
数据库·人工智能·科技
翼龙云_cloud2 小时前
阿里云国际站代理商:ECS弹性伸缩 自动应对流量高峰
运维·网络·数据库·阿里云·架构
吴声子夜歌2 小时前
MongoDB 4.2——安装 MongoDB
数据库·mongodb
吴声子夜歌2 小时前
MongoDB 8.0——MongoDB的安装
数据库·mongodb