ident_current不能用于分组插入前预取id,它返回的是表历史上最后一次成功插入的标识值,而非下一次将生成的值;正确做法是用output子句捕获本次插入产生的id。

IDENT_CURRENT 不能用于分组插入前预取 ID
直接在 INSERT 语句里用 IDENT_CURRENT('table') 拿“下一个要分配的 ID”是错的——它返回的是**该表历史上最后一次成功插入的标识值**,不是下一次将生成的值。比如表刚清空,IDENT_CURRENT('orders') 返回 NULL 或旧值,但真正插入时会从 1 开始;又比如你删了一条 ID=5 的记录,IDENT_CURRENT 还可能返回 5,而下次插入实际是 6。把它当“预测器”用,必然导致主键冲突或关联错乱。
分组插入时真正需要的是“插入后立刻拿到自己这批 ID”
典型场景:先插主表 orders,再用这批新生成的 ID 批量插入子表 order_items。这时必须确保拿到的是**本次插入产生的 ID**,而非别人或历史的 ID。
- ✅ 正确做法:用
OUTPUT子句捕获整批插入结果,例如:INSERT INTO orders (customer_id, total) OUTPUT INSERTED.id, INSERTED.order_no INTO #temp_ids VALUES (101, 99.9), (102, 149.5);
- ✅ 备选方案:用
SCOPE_IDENTITY()+ 循环插入(仅适用于单行或小批量) - ❌ 不要用
IDENT_CURRENT替代——它不保证是你刚插的,也不保证是连续的 - ⚠️ 注意:如果主表插入触发了其他表的级联插入(比如日志),
@@IDENTITY会返回日志表的 ID,彻底跑偏
IDENT_CURRENT 唯一靠谱的分组相关用途:迁移前校验与重置准备
它只适合做“事前检查”,而不是“事中取值”。比如批量导入前确认目标表当前最大 ID,避免和导入数据冲突:
- 查当前最大已用 ID:
SELECT MAX(id) FROM target_table - 查 SQL Server 认为的“下一个该用的 ID”:
SELECT IDENT_CURRENT('target_table') - 两者不一致?说明存在回滚、删除或手动插入导致的断层,需用
DBCC CHECKIDENT('target_table', RESEED, <max_id>)</max_id>对齐 - 权限陷阱:
IDENT_CURRENT需要VIEW DEFINITION权限,没权限时静默返回NULL,容易误判为空表
为什么有人误用 IDENT_CURRENT 插入时取 ID?
早期文档或博客里确实有类似写法:INSERT INTO t(a,b,c) VALUES('x','y',IDENT_CURRENT('t'))。这只有在**表从未插入过、且无并发、且你刚建完表立刻执行**时才偶然正确。现实环境里,只要存在任何并发插入、删除、事务回滚,这个值就不可信。SQL Server 本身没有 LAST_INSERT_ID(),但 OUTPUT 就是它的正解——别绕弯。











