必须用 OUTPUT 子句配合 INSERT 获取刚插入的 ID,因 SCOPE_IDENTITY() 在触发器存在时可能返回错误值;OUTPUT 必须与 INSERT 同语句,INSERTED 代表新行,多列或存变量需用 OUTPUT INTO 表变量或临时表。

能直接拿到,但必须用 OUTPUT 子句配合 INSERT,不能在语句后加 SELECT SCOPE_IDENTITY() —— 后者在并发或触发器存在时可能返回错误值。
OUTPUT 必须和 INSERT 写在同一语句里
很多人写成两步:INSERT 一句,再 SELECT SCOPE_IDENTITY() 一句。这看似合理,但只要表上有 INSTEAD OF 或 AFTER 触发器,SCOPE_IDENTITY() 就可能指向触发器里插入的其他表的 ID,而不是你刚插的那条记录。
正确做法是把 OUTPUT 嵌进 INSERT 语句内部:
INSERT INTO users (name, email)
OUTPUT INSERTED.id
VALUES ('Alice', 'alice@example.com');
注意:INSERTED 是保留关键字,代表刚插入的行;id 是自增列名,需替换成你实际的列名。
要返回多列或存入变量,得用 OUTPUT INTO
如果除了 id 还想取 created_at 或默认值生成的字段,或者要把 ID 存进变量供后续使用,就不能只靠裸 OUTPUT —— 它只能返回结果集。这时要用 OUTPUT INTO 落到临时表或表变量:
-
OUTPUT INTO @temp_table:目标必须是已声明的表变量(不是普通变量) -
OUTPUT INTO #temp:临时表需提前CREATE TABLE,且结构要和OUTPUT列完全匹配 - 不能直接
OUTPUT INTO @id INT—— 表变量必须是二维结构
示例:
DECLARE @output TABLE (id INT, created_at DATETIME2);
INSERT INTO users (name, email)
OUTPUT INSERTED.id, INSERTED.created_at INTO @output
VALUES ('Bob', 'bob@example.com');
SELECT @id = id FROM @output;
OUTPUT 在批量 INSERT 时也可靠,但别漏掉 INSERTED.*
批量插入多行时,OUTPUT INSERTED.id 会返回每行对应的 ID,顺序与 VALUES 或子查询一致。但要注意:
- 如果用
SELECT ... FROM批量插入,OUTPUT返回的行数一定等于实际插入行数,不会少 - 别写成
OUTPUT id(缺INSERTED.前缀)—— SQL Server 会报错:“列名 ‘id’ 不明确” - 若插入时某行违反约束被拒绝,它不会出现在
OUTPUT结果中,也不会中断整个语句(除非设置XACT_ABORT ON)
最常被忽略的是:哪怕只想要一个 ID,也要意识到 OUTPUT 返回的是结果集 —— 在应用程序里取值时,得按结果集第一行第一列读,而不是当成标量处理。有些 ORM 或客户端驱动对单行单列结果集的封装不透明,容易误以为没返回值。

















