必须先开开关、显式列名、再关开关,三步缺一不可;SET IDENTITY_INSERT 是会话级设置,需成对使用且仅对当前连接生效;INSERT 必须显式列出标识列名,否则报错;手动插入值会影响后续自增种子。

不能直接插入,必须先开开关、显式列名、再关开关——漏掉任意一步都会报错。
SET IDENTITY_INSERT 必须配对使用
这个设置是会话级的,只对当前连接生效,且同一时间只能对一个表启用。它不是“打开一次永久有效”,也不是“自动关闭”。如果只执行 SET IDENTITY_INSERT table_name ON 而忘了 OFF,后续常规 INSERT 会失败,报错:Cannot insert explicit value for identity column in table 'xxx' when IDENTITY_INSERT is set to OFF。
-
SET IDENTITY_INSERT table_name ON和SET IDENTITY_INSERT table_name OFF必须成对出现,建议写在同一脚本块里,中间不穿插其他表的ON操作 - 如果脚本中途出错中断,
OFF没执行,可以手动在当前会话中补一句SET IDENTITY_INSERT table_name OFF - 不能跨会话复用:A 会话开了,B 会话仍需自己执行
ON
INSERT 语句必须显式列出标识列名
哪怕你只想改一个值,也必须把标识列写进列名列表,否则 SQL Server 会忽略你传的值,继续走自增逻辑,甚至直接报错:An explicit value for the identity column can only be specified when a column list is used and IDENTITY_INSERT is set to ON。
- 错误写法:
INSERT INTO users VALUES (100, 'Alice')—— 没列名,SQL Server 不认这是往标识列赋值 - 正确写法:
INSERT INTO users (id, name) VALUES (100, 'Alice')——id是标识列名,必须显式写出 - 即使其他列允许 NULL,也不能省略标识列名;哪怕只插一列,也得写全:
INSERT INTO users (id) VALUES (200)
插入值可能影响后续自增种子
手动插入的值不是“临时覆盖”,而是会真实改变 SQL Server 对该标识列的内部计数器。尤其当插入值大于当前最大值时,下次自增就从它+1开始;如果插了个小值(比如现有最大是 100,你插了 50),不会自动调整种子,但可能导致主键冲突或重复风险。
- 查看当前状态:
DBCC CHECKIDENT('users', NORESEED)—— 返回当前标识值和种子 - 重置种子(慎用):
DBCC CHECKIDENT('users', RESEED, 100)—— 下次自增从 101 开始 - 如果插入
VALUES (999),之后普通INSERT会生成 1000,不是从原种子继续 - 权限要求:执行
SET IDENTITY_INSERT需要对该表有ALTER权限
最常被忽略的是:没检查目标表是否真有标识列,或者误以为 ON 后能随便插、不用列名——这两点一错,立刻卡在语法或权限报错上,根本走不到数据写入那步。

















