在 SQLServer 中,触发器是一种特殊的存储过程,它会在表发生 insert、update 或 delete 操作时自动执行。当我们希望某列在插入数据时自动按顺序生成编号,而又不想依赖自增列 identity 的固定规则时,就可以用触发器来实现灵活的自动编号逻辑。

什么是 SQLServer 触发器
触发器依附于表或视图,分为 after 触发器和 instead of 触发器。实现自动编号通常使用 after insert 触发器,即在数据插入成功之后,我们再补充计算编号并写回表中。
创建示例表
我们先创建一张简单的订单表,其中 order_no 就是需要自动编号的字段:
-- 创建订单表
CREATE TABLE orders (
id INT IDENTITY(1,1) PRIMARY KEY,
order_no VARCHAR(20) NULL,
customer_name NVARCHAR(50) NOT NULL
);
编写自动编号触发器
下面的触发器会在每次插入订单后,为该行生成形如 YYYYMMDD0001 的编号:
CREATE TRIGGER trg_orders_auto_no
ON orders
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
-- 遍历刚插入的每一行,生成编号
DECLARE @id INT;
DECLARE cur CURSOR FOR SELECT id FROM inserted;
OPEN cur;
FETCH NEXT FROM cur INTO @id;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 查找当天最大流水号
DECLARE @max_seq INT;
SELECT @max_seq = ISNULL(MAX(CAST(RIGHT(order_no,4) AS INT)),0)
FROM orders
WHERE order_no LIKE CONVERT(VARCHAR(8),GETDATE(),112) + '%';
-- 更新当前行的编号
UPDATE orders
SET order_no = CONVERT(VARCHAR(8),GETDATE(),112)
+ RIGHT('000' + CAST(@max_seq + 1 AS VARCHAR(4)),4)
WHERE id = @id;
FETCH NEXT FROM cur INTO @id;
END
CLOSE cur;
DEALLOCATE cur;
END;
测试自动编号效果
插入两条测试数据,不需要提供 order_no:
INSERT INTO orders (customer_name) VALUES ('张三');
INSERT INTO orders (customer_name) VALUES ('李四');
SELECT id, order_no, customer_name FROM orders;
执行后可以看到 order_no 字段已经被触发器自动填成了类似 202401010001 和 202401010002 的值。
注意事项
- 触发器内尽量避免复杂逻辑,否则会影响插入性能。
- 高并发场景下,上述写法可能出现编号重复,建议加表锁或使用序列 sequence。
- 如果表已有 identity 列,也可以直接用它做基础编号,只是格式需自行拼接。
自动编号的本质是把编号规则从程序端移到数据库端,用触发器可以保证无论哪边写入数据,编号都统一生成。
小结
通过 after insert 触发器,我们可以很方便地在不改动业务代码的情况下,为 SQLServer 表实现自动编号。理解触发器的执行时机和 inserted 临时表,是写好这类逻辑的关键。